# Worked solutions Complete records for [the tour](/corpus/lab/): every command with the output it produced on the pinned tool. Compare verdicts and proof shape when you repeat them; the long hashes in answer footers match whenever the inputs match. ## Before you start Run everything below from the extracted bundle root (`corpus-lab/`). The tour materials, plus the silent scratch directory setup: ```shell ls -d fixtures/parcels-* ls templates/*.md mkdir -p /tmp/lab-work ``` ```text fixtures/parcels-appeals fixtures/parcels-appeals-0.2.0 fixtures/parcels-case1 fixtures/parcels-fees fixtures/parcels-fees-0.3.0 fixtures/parcels-fees-0.4.0 fixtures/parcels-iface fixtures/parcels-iface-0.2.0 fixtures/parcels-registry fixtures/parcels-registry-0.3.0 templates/corpus-charter.md templates/public-vocabulary-contract.md templates/release-checklist.md templates/review-checklist.md templates/shared-dependency-change.md templates/vocabulary-decision-record.md ``` The ten parcels fixture states, the six templates the tour copies from, and no output from the directory setup. The bundle's `PINNED.md` names the source revision these transcripts were recorded against; the pack hashes further down pin every fixture's bytes behind that revision. The tour runs on one build only — the public `law-v0.1.1` release, checked below on macOS arm64 (the Linux x64 binary hash is `sha256:be8b4fbb…`; both are pinned in the bundle's `PINNED.md`): ```shell law version ``` ```text law 0.1.1 semantics: law.core/0.2 std for language 0.2: 0.2.0 lawql: lawql/1 (queryResult 0.1) binary hash: sha256:cfa7c17232f2dc594e665dbbf2ad3c154675797ef4be07ef7d758c9abfb80a28 ``` When two installs disagree, compare the first line first; the last line identifies the exact bytes behind each install, so it differs per platform. Do not substitute the checkout `./law` launcher for the tour: it builds newer source whose 0.2.6 numerals disagree with these 0.2.4 fixtures (the fee scenario fails there). The checkout launcher is needed only where a section says so explicitly. The public composition is smaller than the checkout one. Structure and generator commands are absent from it: ```shell law query --list 2>&1 | head -n 1 law gen pinning 2>&1 | head -n 1 ``` ```text law: unknown command query law: unknown command gen ``` The Structure answers section and the two pinning runs below therefore carry their own checkout prerequisites; everything else runs on the public build above. ## Scenario transcripts Shared vocabulary, two scenarios: ```shell law test fixtures/parcels-iface ``` ```text law test labparcels.iface: world labparcels.iface ok [labparcels.iface#authored] tests/01-owns-ok.lawtest / urn:lab:parcels:iface:owns-ok ok [labparcels.iface#authored] tests/02-owns-unknown.lawtest / urn:lab:parcels:iface:owns-unknown total: 2 checked, 2 passed, 0 failed, 0 not run; code 0 ``` Registry act, four scenarios: ```shell law test fixtures/parcels-registry ``` ```text law test labparcels.registry: world labparcels.registry, labparcels.iface ok [labparcels.registry#authored] tests/01-registered-ok.lawtest / urn:lab:parcels:registry:registered-ok ok [labparcels.registry#authored] tests/02-registered-missing-kind.lawtest / urn:lab:parcels:registry:registered-missing-kind ok [labparcels.registry#authored] tests/03-transfer-ok.lawtest / urn:lab:parcels:registry:transfer-ok ok [labparcels.registry#authored] tests/04-transfer-stranger.lawtest / urn:lab:parcels:registry:transfer-stranger total: 4 checked, 4 passed, 0 failed, 0 not run; code 0 ``` Fees, five scenarios: ```shell law test fixtures/parcels-fees ``` ```text law test labparcels.fees: world labparcels.fees, labparcels.iface, labparcels.registry ok [labparcels.fees#authored] tests/01-fee-residential-ok.lawtest / urn:lab:parcels:fees:residential-ok ok [labparcels.fees#authored] tests/02-fee-commercial-ok.lawtest / urn:lab:parcels:fees:commercial-ok ok [labparcels.fees#authored] tests/03-fee-garden-ok.lawtest / urn:lab:parcels:fees:garden-ok ok [labparcels.fees#authored] tests/04-fee-unregistered.lawtest / urn:lab:parcels:fees:unregistered ok [labparcels.fees#authored] tests/05-fee-wrong-amount.lawtest / urn:lab:parcels:fees:wrong-amount total: 5 checked, 5 passed, 0 failed, 0 not run; code 0 ``` Appeals, three scenarios: ```shell law test fixtures/parcels-appeals ``` ```text law test labparcels.appeals: world labparcels.appeals, labparcels.iface, labparcels.registry ok [labparcels.appeals#authored] tests/01-appeal-timely-ok.lawtest / urn:lab:parcels:appeals:timely-ok ok [labparcels.appeals#authored] tests/02-appeal-late.lawtest / urn:lab:parcels:appeals:late ok [labparcels.appeals#authored] tests/03-appeal-unregistered.lawtest / urn:lab:parcels:appeals:unregistered total: 3 checked, 3 passed, 0 failed, 0 not run; code 0 ``` Worked case, four scenarios over the five-package world: ```shell law test fixtures/parcels-case1 ``` ```text law test labparcels.case1: world labparcels.case1, labparcels.appeals, labparcels.fees, labparcels.iface, labparcels.registry ok [labparcels.case1#authored] tests/01-worked-parcel.lawtest / urn:lab:parcels:case1:fee ok [labparcels.case1#authored] tests/01-worked-parcel.lawtest / urn:lab:parcels:case1:transfer ok [labparcels.case1#authored] tests/01-worked-parcel.lawtest / urn:lab:parcels:case1:appeal ok [labparcels.case1#authored] tests/01-worked-parcel.lawtest / urn:lab:parcels:case1:wrong-fee total: 4 checked, 4 passed, 0 failed, 0 not run; code 0 ``` The rate revision, five scenarios over the original world: ```shell law test fixtures/parcels-fees-0.3.0 ``` ```text law test labparcels.fees: world labparcels.fees, labparcels.iface, labparcels.registry ok [labparcels.fees#authored] tests/01-fee-residential-ok.lawtest / urn:lab:parcels:fees:residential-ok ok [labparcels.fees#authored] tests/02-fee-commercial-ok.lawtest / urn:lab:parcels:fees:commercial-ok ok [labparcels.fees#authored] tests/03-fee-garden-ok.lawtest / urn:lab:parcels:fees:garden-ok ok [labparcels.fees#authored] tests/04-fee-unregistered.lawtest / urn:lab:parcels:fees:unregistered ok [labparcels.fees#authored] tests/05-fee-wrong-amount.lawtest / urn:lab:parcels:fees:wrong-amount total: 5 checked, 5 passed, 0 failed, 0 not run; code 0 ``` The renamed vocabulary, two scenarios: ```shell law test fixtures/parcels-iface-0.2.0 ``` ```text law test labparcels.iface: world labparcels.iface ok [labparcels.iface#authored] tests/01-holds-ok.lawtest / urn:lab:parcels:iface:holds-ok ok [labparcels.iface#authored] tests/02-holds-unknown.lawtest / urn:lab:parcels:iface:holds-unknown total: 2 checked, 2 passed, 0 failed, 0 not run; code 0 ``` The migrated act, four scenarios: ```shell law test fixtures/parcels-registry-0.3.0 ``` ```text law test labparcels.registry: world labparcels.registry, labparcels.iface ok [labparcels.registry#authored] tests/01-registered-ok.lawtest / urn:lab:parcels:registry:registered-ok ok [labparcels.registry#authored] tests/02-registered-missing-kind.lawtest / urn:lab:parcels:registry:registered-missing-kind ok [labparcels.registry#authored] tests/03-transfer-ok.lawtest / urn:lab:parcels:registry:transfer-ok ok [labparcels.registry#authored] tests/04-transfer-stranger.lawtest / urn:lab:parcels:registry:transfer-stranger total: 4 checked, 4 passed, 0 failed, 0 not run; code 0 ``` The fee consumer on the renamed line, five scenarios: ```shell law test fixtures/parcels-fees-0.4.0 ``` ```text law test labparcels.fees: world labparcels.fees, labparcels.iface, labparcels.registry ok [labparcels.fees#authored] tests/01-fee-residential-ok.lawtest / urn:lab:parcels:fees:residential-ok ok [labparcels.fees#authored] tests/02-fee-commercial-ok.lawtest / urn:lab:parcels:fees:commercial-ok ok [labparcels.fees#authored] tests/03-fee-garden-ok.lawtest / urn:lab:parcels:fees:garden-ok ok [labparcels.fees#authored] tests/04-fee-unregistered.lawtest / urn:lab:parcels:fees:unregistered ok [labparcels.fees#authored] tests/05-fee-wrong-amount.lawtest / urn:lab:parcels:fees:wrong-amount total: 5 checked, 5 passed, 0 failed, 0 not run; code 0 ``` The appeal consumer on the renamed line, three scenarios: ```shell law test fixtures/parcels-appeals-0.2.0 ``` ```text law test labparcels.appeals: world labparcels.appeals, labparcels.iface, labparcels.registry ok [labparcels.appeals#authored] tests/01-appeal-timely-ok.lawtest / urn:lab:parcels:appeals:timely-ok ok [labparcels.appeals#authored] tests/02-appeal-late.lawtest / urn:lab:parcels:appeals:late ok [labparcels.appeals#authored] tests/03-appeal-unregistered.lawtest / urn:lab:parcels:appeals:unregistered total: 3 checked, 3 passed, 0 failed, 0 not run; code 0 ``` ## Answers The answer text is printed in Russian: the public release renders answers with the `law.verb.ru` verbalization pack, while the fixture names (`fee_due`, `parcel`, `p1`) stay English. The phrases that recur in every record below: | Russian line | Meaning | |---|---| | `# Ответ по делу` | Case answer (page title) | | `> **Дисклеймер.** Ответ получен исполнением…` | Disclaimer: the answer comes from executing a formalized model on the case data; it is neither the official text of the act nor a legal opinion | | `## Вопрос` / `Установлено ли, что «X»?` | Question / Is it established that X? | | `## Ответ` / `Вычисление завершено.` | Answer / The evaluation completed | | `Установлено, что «X»; обратное не установлено.` | X is established; its opposite is not | | `Не установлено ни что «X», ни обратное.` | Neither X nor its opposite is established (the model derives nothing either way; this is not a claim that X is false) | | `## Основания` | Grounds | | `По правилу «R»` | By rule R | | `основание: фрагмент article/N издания «E» — «…»` | Ground: fragment article/N of edition E, quoted | | `Факт дела` | Case fact | | `см. шаг N` | See step N (a repeated step printed once) | | `сумма`, `собственник`, `день` | Argument labels: amount, owner, day | | `*Вопрос … · результат … · resultHash … · программа … · вербализация … · язык … · подробность: полное дерево*` | Footer: question id, result id, result hash, program hash, verbalization pack, language, detail level (full tree) | The fee question: ```shell law ask fixtures/parcels-case1 --case ParcelTransfer --query-json fixtures/parcels-case1/queries/fee-answered.json --format text ``` ```text # Ответ по делу > **Дисклеймер.** Ответ получен исполнением формализованной модели на данных дела. Это не официальный текст акта и не юридическое заключение. ## Вопрос Установлено ли, что «fee_due» (parcel: `p1`, сумма: 100)? ## Ответ Вычисление завершено. Установлено, что «fee_due» (parcel: `p1`, сумма: 100); обратное не установлено. ## Основания - 1. По правилу «FeeResidential»: «fee_due» (parcel: `p1`, сумма: 100) - 2. По правилу «RegistrationComplete»: «registered» (parcel: `p1`) основание: фрагмент article/1 издания «PARCEL_REGISTRY_RULES_EN» — «1. Registration of parcels A parcel counts as registered when an owner holds it and a kind is recorded for it. A holding without a recorded kind registers nothing.» - 3. Факт дела: «owns» (собственник: `amy`, parcel: `p1`) - 4. Факт дела: «kind_of» (parcel: `p1`, kind: «residential») - см. шаг 4 --- *Вопрос `urn:law:lab:parcels:case1#case/ParcelTransfer/query/fee-answered` · результат `urn:result:case1#case/ParcelTransfer/query/fee-answered` · resultHash `sha256:dc3120593dd12d014b6fb50adb5a05403b0fbb43b6686d02ff4dcbfcf693c677` · программа `sha256:f219f1832a4945e55f3227f424ad69df7d4cab5c8691c6dd37e8ce7067eab182` · вербализация law.verb.ru@0.39.0 · язык ru-KZ · подробность: полное дерево* ``` The transfer question: ```shell law ask fixtures/parcels-case1 --case ParcelTransfer --query-json fixtures/parcels-case1/queries/transfer-answered.json --format text ``` ```text # Ответ по делу > **Дисклеймер.** Ответ получен исполнением формализованной модели на данных дела. Это не официальный текст акта и не юридическое заключение. ## Вопрос Установлено ли, что «transfer_granted» (parcel: `p1`, from: `amy`, to: `bob`)? ## Ответ Вычисление завершено. Установлено, что «transfer_granted» (parcel: `p1`, from: `amy`, to: `bob`); обратное не установлено. ## Основания - 1. По правилу «TransferGranted»: «transfer_granted» (parcel: `p1`, from: `amy`, to: `bob`) основание: фрагмент article/2 издания «PARCEL_REGISTRY_RULES_EN» — «2. Transfer of parcels A registered parcel transfers when its recorded owner asks for the transfer to a new owner. An ask from anyone else grants nothing.» - 2. По правилу «RegistrationComplete»: «registered» (parcel: `p1`) основание: фрагмент article/1 издания «PARCEL_REGISTRY_RULES_EN» — «1. Registration of parcels A parcel counts as registered when an owner holds it and a kind is recorded for it. A holding without a recorded kind registers nothing.» - 3. Факт дела: «owns» (собственник: `amy`, parcel: `p1`) - 4. Факт дела: «kind_of» (parcel: `p1`, kind: «residential») - 5. Факт дела: «transfer_request» (parcel: `p1`, from: `amy`, to: `bob`) - см. шаг 3 --- *Вопрос `urn:law:lab:parcels:case1#case/ParcelTransfer/query/transfer-answered` · результат `urn:result:case1#case/ParcelTransfer/query/transfer-answered` · resultHash `sha256:8c5deca4fb4bcf6fcbdda27f6715aba5807de7942803db573213f05b7ff000e7` · программа `sha256:f219f1832a4945e55f3227f424ad69df7d4cab5c8691c6dd37e8ce7067eab182` · вербализация law.verb.ru@0.39.0 · язык ru-KZ · подробность: полное дерево* ``` The appeal question: ```shell law ask fixtures/parcels-case1 --case ParcelTransfer --query-json fixtures/parcels-case1/queries/appeal-answered.json --format text ``` ```text # Ответ по делу > **Дисклеймер.** Ответ получен исполнением формализованной модели на данных дела. Это не официальный текст акта и не юридическое заключение. ## Вопрос Установлено ли, что «appeal_timely» (parcel: `p1`)? ## Ответ Вычисление завершено. Установлено, что «appeal_timely» (parcel: `p1`); обратное не установлено. ## Основания - 1. По правилу «AppealTimely»: «appeal_timely» (parcel: `p1`) - 2. По правилу «RegistrationComplete»: «registered» (parcel: `p1`) основание: фрагмент article/1 издания «PARCEL_REGISTRY_RULES_EN» — «1. Registration of parcels A parcel counts as registered when an owner holds it and a kind is recorded for it. A holding without a recorded kind registers nothing.» - 3. Факт дела: «owns» (собственник: `amy`, parcel: `p1`) - 4. Факт дела: «kind_of» (parcel: `p1`, kind: «residential») - 5. Факт дела: «appeal_filed» (parcel: `p1`, день: 25) - 6. Факт дела: «appeal_window» (parcel: `p1`, from_day: 10, to_day: 40) --- *Вопрос `urn:law:lab:parcels:case1#case/ParcelTransfer/query/appeal-answered` · результат `urn:result:case1#case/ParcelTransfer/query/appeal-answered` · resultHash `sha256:eb9b1cf945f951ac18d09abb8eb6ece82566f0f37c4b8fa6da0e36becf449da1` · программа `sha256:f219f1832a4945e55f3227f424ad69df7d4cab5c8691c6dd37e8ce7067eab182` · вербализация law.verb.ru@0.39.0 · язык ru-KZ · подробность: полное дерево* ``` How to read these records: the verdict line says the conclusion is established and its opposite is not; the grounds below it name the rule, the case facts, and — for registry steps — the pinned article each step leans on. The shared lines marked as repeated steps point back at an earlier step instead of printing it twice. Why the fee question spells the amount the way it does: the rule head `fee_due(p, 100)` compiles the literal into the shared number shape, and the question file must use that same shape to meet it. The compiled head, read from the pinned fees file inside the case world: ```json fixture="parcels-case1/deps/labparcels.fees.lawir.json" {"args": [{"kind": "var", "var": "v0"}, {"kind": "value", "type": {"name": "urn:law:std#Integer"}, "value": 250}], "kind": "literal", "polarity": "positive", "predicate": "urn:law:lab:parcels:fees#fee_due"} ``` That row is the commercial rule; the residential rule the question meets carries `100` in the same position. The fee question file therefore passes the amount as an Integer `100` in the same typed value shape, not as a bare literal. Scenario files need no such care: they share the surface spelling with the rules, so `100` there meets `100` in the rule head. ## Structure answers Prerequisites for this section only: a full repository checkout and its `./law` launcher, run from the repository root. The public `law` composition has no `query` command (`law: unknown command query`), so these six runs cannot come from the bundle route. The catalog holds twenty-two entries; the six question entries read (descriptions are printed in Russian; the English reading follows the listing): ```text anchors-of (node, pkg) — На какие закреплённые фрагменты опирается узел — акт, локатор и фрагмент каждого якоря. imports-of (pkg) — Что импортирует пакет — имена импортированных пакетов и их закреплённые semanticHash. links-of (node, pkg) — Все типизированные связи узла по отношению links — produces, reads, anchored, alias, subtype. producers (predicate, pkg) — Кто производит предикат в пакете — правила с этой головой, их сила, полярность и якоря. readers (predicate, pkg) — Кто читает предикат — литералы тел правил, норм и ограничений (головы исключены: их перечисляет producers); pkg может быть глобом, тогда видно чтение из других пакетов. type-step (type, pkg) — Один шаг цепочки типов субъекта — alias или subtype от названного типа к цели; следующий шаг — тот же вопрос с полученным to и пакетом цели. ``` In English: | Question | What it answers | |---|---| | `anchors-of (node, pkg)` | Which pinned fragments a node rests on: the act, locator, and fragment of each anchor | | `imports-of (pkg)` | What a package imports: the imported package names and their pinned `semanticHash` | | `links-of (node, pkg)` | All typed links of a node in the `links` relation: produces, reads, anchored, alias, subtype | | `producers (predicate, pkg)` | Who produces a predicate in a package: rules with that head, their strength, polarity, and anchors | | `readers (predicate, pkg)` | Who reads a predicate: body literals of rules, norms, and constraints (heads are excluded; `producers` lists them); `pkg` may be a glob, which shows reads from other packages | | `type-step (type, pkg)` | One step of a subject's type chain: an alias or subtype from the named type to its target; the next step is the same question with the returned `to` and the target's package | Who derives the registered flag: ```shell ./law query producers --project docs/corpus/lab/fixtures/parcels-registry --param predicate=urn:law:lab:parcels:registry#registered --param pkg=labparcels.registry ``` ```text 1. producer: "urn:law:lab:parcels:registry#RegistrationComplete" | strength: "strict" | polarity: "positive" | anchors: [{"act":"urn:law:lab:parcels:registry#PARCEL_REGISTRY_RULES","anchor":"urn:law:lab:parcels:registry#PARCEL_RULE_1","locator":"article/1","path":"labparcels.registry.lawir.json"}] nodes: urn:law:lab:parcels:registry#PARCEL_REGISTRY_RULES, urn:law:lab:parcels:registry#PARCEL_RULE_1, urn:law:lab:parcels:registry#RegistrationComplete, urn:law:lab:parcels:registry#kind_of, urn:law:lab:parcels:registry#registered label: Parcel Registry Rules (fictional training text) file: labparcels.registry.lawir.json file: labparcels.registry.lawir.json source: article/1 — labparcels.registry.lawir.json label: recorded kind of the parcel file: labparcels.registry.lawir.json label: parcel is registered file: labparcels.registry.lawir.json Rows: 1; packages in snapshot: 1. ``` Who reads the holding link across the lab world: ```shell ./law query readers --project docs/corpus/lab/fixtures/parcels-case1 --param predicate=urn:law:lab:parcels:iface#owns --param pkg='labparcels.*' ``` ```text 1. reader: "urn:law:lab:parcels:registry#RegistrationComplete" | context: "body.items[1].formula" | polarity: "positive" | package: "urn:law:lab:parcels:registry" nodes: urn:law:lab:parcels:iface#owns, urn:law:lab:parcels:registry#RegistrationComplete label: owner holds the parcel file: deps/labparcels.iface.lawir.json source: article/1 — deps/labparcels.registry.lawir.json 2. reader: "urn:law:lab:parcels:registry#TransferGranted" | context: "body.items[2].formula" | polarity: "positive" | package: "urn:law:lab:parcels:registry" nodes: urn:law:lab:parcels:iface#owns, urn:law:lab:parcels:registry#TransferGranted label: owner holds the parcel file: deps/labparcels.iface.lawir.json source: article/2 — deps/labparcels.registry.lawir.json Rows: 2; packages in snapshot: 5. ``` What the registration rule leans on: ```shell ./law query anchors-of --project docs/corpus/lab/fixtures/parcels-registry --param node=urn:law:lab:parcels:registry#RegistrationComplete --param pkg=labparcels.registry ``` ```text 1. fragment: "urn:law:lab:parcels:registry#PARCEL_RULE_1" | act: "urn:law:lab:parcels:registry#PARCEL_REGISTRY_RULES" | locator: "article/1" nodes: urn:law:lab:parcels:registry#PARCEL_REGISTRY_RULES, urn:law:lab:parcels:registry#PARCEL_RULE_1, urn:law:lab:parcels:registry#RegistrationComplete label: Parcel Registry Rules (fictional training text) file: labparcels.registry.lawir.json file: labparcels.registry.lawir.json source: article/1 — labparcels.registry.lawir.json Rows: 1; packages in snapshot: 1. ``` How the parcel type resolves: ```shell ./law query type-step --project docs/corpus/lab/fixtures/parcels-registry --param type=urn:law:lab:parcels:registry#Parcel --param pkg=labparcels.registry ``` ```text 1. step: "alias" | to: "urn:law:lab:parcels:iface#Parcel" nodes: urn:law:lab:parcels:registry#Parcel file: labparcels.registry.lawir.json Rows: 1; packages in snapshot: 1. ``` What the case package pulls in: ```shell ./law query imports-of --project docs/corpus/lab/fixtures/parcels-case1 --param pkg=labparcels.case1 ``` ```text 1. imported: "labparcels.appeals" | semantic_hash: "sha256:0000000000000000000000000000000000000000000000000000000000000000" 2. imported: "labparcels.fees" | semantic_hash: "sha256:0000000000000000000000000000000000000000000000000000000000000000" 3. imported: "labparcels.iface" | semantic_hash: "sha256:0000000000000000000000000000000000000000000000000000000000000000" 4. imported: "labparcels.registry" | semantic_hash: "sha256:0000000000000000000000000000000000000000000000000000000000000000" Rows: 4; packages in snapshot: 1. ``` Those four zero hashes need a gloss. Each `semantic_hash` is the pinned digest the importing package records for one imported package in its own compiled imports table — not a digest computed over the dependency bytes at query time. The machine-readable form of the same question names the snapshot the rows come from: the case package's own compiled program, one package: ```shell ./law query imports-of --project docs/corpus/lab/fixtures/parcels-case1 --param pkg=labparcels.case1 --format json | python3 -c "import json,sys; r=json.load(sys.stdin); print(json.dumps(r['manifest']['corpus'],indent=1))" ``` ```text [ { "package": "labparcels.case1", "semanticHash": "sha256:825c4816a2131db5bae1f1080363969ff9474d1f43c7f44ec6e6b3b335873c87" } ] ``` The snapshot digest (`825c4816…`) is the checkout toolchain's compilation of the case program — it differs from the public-release program digest in the answer footers (`f219f183…`), because the two compositions compile numerals differently (Integer versus Number). The rows above come from that same checkout run over the shipped 0.2.4 dependency bytes. In these lab snapshots the per-import pins are unset, so every row reads zero. The pins that actually lock the world live beside them in the case lockfile, one content digest per imported package: ```shell python3 -c "import json; lock=json.load(open('fixtures/parcels-case1/law.lock')); [print(p['name']+'@'+p['version'], p['contentHash']) for p in lock['packages']]" ``` ```text labparcels.appeals@0.1.0 sha256:92860bd5cd0ac02edbe666965d8430fb360dc5f938fcabaee4d83f1f95b7df6e labparcels.fees@0.2.0 sha256:dfe81269bfe070987ada69e4c2545e9c31a755aa1600be72a8242a00c30dbde4 labparcels.iface@0.1.0 sha256:23b7a38c3f80dc22015fe983e6ae21083e4d52d9ef1309a5e36d964cf0a31ac2 labparcels.registry@0.1.0 sha256:15b5bd7fe6f4260b5e2f94e9c8ba5af53150e36c55365b3d463e5bc34215368f ``` Those four digests match the packed content digests quoted in the versions exercise, and each matches the pinned bytes the lockfile check verifies. Read together: one rule derives the registered flag; two rules read the holding link; the registration rule leans on the first article; the registry parcel type is an alias of the shared parcel type; the case package pulls in all four lab packages. A named question without its package parameter is refused; the tool names the missing piece. ## Provenance answers The pinning check and the audit below need the checkout route: run both from the repository root with `./law`. The public composition has neither `gen` nor the lint catalog the audit's last line reports on. The remaining checks in this section run on the public route from the bundle root. The pinning check, flagless form: ```shell ./law gen pinning docs/corpus/lab/fixtures/parcels-registry ``` ```text ✓ pinning.toml → sources.law [en-US] (2 articles) ``` The audit over the same fixture: ```shell ./law audit docs/corpus/lab/fixtures/parcels-registry ``` ```text law audit labparcels.registry — formalization measure §33.1 (E-0249), profile static CLIR lowered from sources (imports: deps); freshness: verified levels not computed by this implementation: STRUCTURED, SEMANTIC — urn:law:lab:parcels:registry#PARCEL_REGISTRY_RULES_TXT — unit: пункт (point), path declared; units 2, excluded 0 EXECUTABLE 2, ANCHORED 0, SOURCE_ONLY 0, without nodes 0; reading-only under §152: 0 aggregated model (detail not confirmed): none text coverage: 317 of 369 bytes (85.9 %), fragments 2 form (LawQL catalog lints on fresh snapshot, DECISION-0394): detectors 16, findings 0 dangling premises: 0 (unsupplied by package 0, enum variants in body 0) one-way premises: 0 of 2 rules ``` Both articles executable, both fragments covering most of the pinned bytes, sixteen structural checks with no findings. The small articles file beside the pinned text declares the denominator the measure counts against; without it the publication reports no text and the measure is not taken. The import-block check: ```shell law fix imports fixtures/parcels-registry --check ``` ```text fixtures/parcels-registry `use self` blocks are canonical ``` The manifest reading: ```shell law engine manifest fixtures/parcels-registry/law.toml ``` ```text {"authoring":{"local_imports":"explicit"},"dependencies":{"labparcels.iface":"0.1.0"},"features":{"semanticLayer":"L3"},"package":{"language":"0.2","name":"labparcels.registry","namespace":"urn:law:lab:parcels:registry","version":"0.1.0"}} ``` The lock readings, one per fixture: ```shell law engine lock fixtures/parcels-iface --check law engine lock fixtures/parcels-registry --check law engine lock fixtures/parcels-fees --check law engine lock fixtures/parcels-appeals --check law engine lock fixtures/parcels-case1 --check ``` ```text lock: fixtures/parcels-iface/law.lock matches law.toml and resources lock: fixtures/parcels-registry/law.lock matches law.toml and resources lock: fixtures/parcels-fees/law.lock matches law.toml and resources lock: fixtures/parcels-appeals/law.lock matches law.toml and resources lock: fixtures/parcels-case1/law.lock matches law.toml and resources ``` The offline install: ```shell law install --offline --project fixtures/parcels-registry ``` ```text all in place: deps/ and resources already match law.lock no changes ``` Statics pass on all five fixtures as well; each `law engine check` answers `check OK` with the fixture name. ## Versions exercise Pack the five fixtures. Each answer names the artifact directory and two hashes; the content hash pins the package bytes, the world hash pins the package with its closure: ```shell law pack --out /tmp/lab-work/artifacts/iface --project fixtures/parcels-iface law pack --out /tmp/lab-work/artifacts/registry --project fixtures/parcels-registry law pack --out /tmp/lab-work/artifacts/fees --project fixtures/parcels-fees law pack --out /tmp/lab-work/artifacts/appeals --project fixtures/parcels-appeals law pack --out /tmp/lab-work/artifacts/case1 --project fixtures/parcels-case1 ``` ```text labparcels.iface@0.1.0 → /tmp/lab-work/artifacts/iface: contentHash sha256:23b7a38c3f80dc22015fe983e6ae21083e4d52d9ef1309a5e36d964cf0a31ac2, worldHash sha256:23b7a38c3f80dc22015fe983e6ae21083e4d52d9ef1309a5e36d964cf0a31ac2, 3 files labparcels.registry@0.1.0 → /tmp/lab-work/artifacts/registry: contentHash sha256:15b5bd7fe6f4260b5e2f94e9c8ba5af53150e36c55365b3d463e5bc34215368f, worldHash sha256:13ef321e7bf4e5e44b45f2142e1f000e2ba4ffbf749cb3694041993bb6346ef2, 3 files labparcels.fees@0.2.0 → /tmp/lab-work/artifacts/fees: contentHash sha256:dfe81269bfe070987ada69e4c2545e9c31a755aa1600be72a8242a00c30dbde4, worldHash sha256:056a48336aba96920988682a4a72e723c35a9d177f094d549f79df1739322b7a, 3 files labparcels.appeals@0.1.0 → /tmp/lab-work/artifacts/appeals: contentHash sha256:92860bd5cd0ac02edbe666965d8430fb360dc5f938fcabaee4d83f1f95b7df6e, worldHash sha256:866374f2e79343b9cef623feeef6961574b32a6fce02c2533d486eb97fc1012e, 3 files labparcels.case1@0.1.0 → /tmp/lab-work/artifacts/case1: contentHash sha256:14ae7edbf58225f3fdf1cc7b5f21cb14ac33fb223795a2834d4c8d765b6f0cdc, worldHash sha256:59059bde677910196f9d3533e782716e9cd776e21e2b873119a3c35d191bce10, 3 files ``` Publish the five artifacts into one throwaway registry. The first publish creates the registry; each publish then lists the known versions and the descriptor and blob files it wrote: ```shell law publish /tmp/lab-work/artifacts/iface --registry lab=/tmp/lab-work/registry law publish /tmp/lab-work/artifacts/registry --registry lab=/tmp/lab-work/registry law publish /tmp/lab-work/artifacts/fees --registry lab=/tmp/lab-work/registry law publish /tmp/lab-work/artifacts/appeals --registry lab=/tmp/lab-work/registry law publish /tmp/lab-work/artifacts/case1 --registry lab=/tmp/lab-work/registry ``` ```text registry lab created: /tmp/lab-work/registry labparcels.iface@0.1.0 → lab (/tmp/lab-work/registry): contentHash sha256:23b7a38c3f80dc22015fe983e6ae21083e4d52d9ef1309a5e36d964cf0a31ac2, worldHash sha256:23b7a38c3f80dc22015fe983e6ae21083e4d52d9ef1309a5e36d964cf0a31ac2 versions labparcels.iface: 0.1.0 changed: p/labparcels.iface/0.1.0/package.lawir.json changed: p/labparcels.iface/0.1.0/world.lawir.json changed: p/labparcels.iface/0.1.0.json labparcels.registry@0.1.0 → lab (/tmp/lab-work/registry): contentHash sha256:15b5bd7fe6f4260b5e2f94e9c8ba5af53150e36c55365b3d463e5bc34215368f, worldHash sha256:13ef321e7bf4e5e44b45f2142e1f000e2ba4ffbf749cb3694041993bb6346ef2 versions labparcels.registry: 0.1.0 changed: p/labparcels.registry/0.1.0/package.lawir.json changed: p/labparcels.registry/0.1.0/world.lawir.json changed: p/labparcels.registry/0.1.0.json labparcels.fees@0.2.0 → lab (/tmp/lab-work/registry): contentHash sha256:dfe81269bfe070987ada69e4c2545e9c31a755aa1600be72a8242a00c30dbde4, worldHash sha256:056a48336aba96920988682a4a72e723c35a9d177f094d549f79df1739322b7a versions labparcels.fees: 0.2.0 changed: p/labparcels.fees/0.2.0/package.lawir.json changed: p/labparcels.fees/0.2.0/world.lawir.json changed: p/labparcels.fees/0.2.0.json labparcels.appeals@0.1.0 → lab (/tmp/lab-work/registry): contentHash sha256:92860bd5cd0ac02edbe666965d8430fb360dc5f938fcabaee4d83f1f95b7df6e, worldHash sha256:866374f2e79343b9cef623feeef6961574b32a6fce02c2533d486eb97fc1012e versions labparcels.appeals: 0.1.0 changed: p/labparcels.appeals/0.1.0/package.lawir.json changed: p/labparcels.appeals/0.1.0/world.lawir.json changed: p/labparcels.appeals/0.1.0.json labparcels.case1@0.1.0 → lab (/tmp/lab-work/registry): contentHash sha256:14ae7edbf58225f3fdf1cc7b5f21cb14ac33fb223795a2834d4c8d765b6f0cdc, worldHash sha256:59059bde677910196f9d3533e782716e9cd776e21e2b873119a3c35d191bce10 versions labparcels.case1: 0.1.0 changed: p/labparcels.case1/0.1.0/package.lawir.json changed: p/labparcels.case1/0.1.0/world.lawir.json changed: p/labparcels.case1/0.1.0.json ``` Currency against that registry reports every pin up to date, exit 0: ```shell law outdated --project fixtures/parcels-fees --registry lab=/tmp/lab-work/registry law outdated --project fixtures/parcels-case1 --registry lab=/tmp/lab-work/registry ``` ```text lab ← /tmp/lab-work/registry (--registry) labparcels.iface@0.1.0 [lab]: up to date labparcels.registry@0.1.0 [lab]: up to date lab ← /tmp/lab-work/registry (--registry) labparcels.appeals@0.1.0 [lab]: up to date labparcels.fees@0.2.0 [lab]: up to date labparcels.iface@0.1.0 [lab]: up to date labparcels.registry@0.1.0 [lab]: up to date ``` Author revision 0.2.0 of the registry package on a scratch copy. The in-place rewrites use `perl`, which behaves the same on both supported platforms; the appended block is the only addition to the rules file: ```shell cp -r fixtures/parcels-registry /tmp/lab-work/reg02 perl -pi -e 's/^version = "0.1.0"/version = "0.2.0"/' /tmp/lab-work/reg02/law.toml perl -pi -e 's/package labparcels.registry version "0.1.0"/package labparcels.registry version "0.2.0"/' /tmp/lab-work/reg02/package.law /tmp/lab-work/reg02/sources.law /tmp/lab-work/reg02/tests/*.lawtest cat >> /tmp/lab-work/reg02/package.law <<'EOF' pub relation kind_recorded(parcel: Parcel) kind derived { label en unofficial "parcel has a recorded kind"; } @source(PARCEL_RULE_1) rule KindRecorded strict { for p: Parcel; for k: ParcelKind; when kind_of(p, k); then kind_recorded(p); } EOF law test /tmp/lab-work/reg02 ``` Bump the package headers only, not the import line, which keeps pointing at the shared vocabulary at 0.1.0. The copied pins still hold, so the four scenarios pass with no rewiring step: ```text law test labparcels.registry: world labparcels.registry, labparcels.iface ok [labparcels.registry#authored] tests/01-registered-ok.lawtest / urn:lab:parcels:registry:registered-ok ok [labparcels.registry#authored] tests/02-registered-missing-kind.lawtest / urn:lab:parcels:registry:registered-missing-kind ok [labparcels.registry#authored] tests/03-transfer-ok.lawtest / urn:lab:parcels:registry:transfer-ok ok [labparcels.registry#authored] tests/04-transfer-stranger.lawtest / urn:lab:parcels:registry:transfer-stranger total: 4 checked, 4 passed, 0 failed, 0 not run; code 0 ``` Then pack and publish the revision into the same registry: ```shell law pack --out /tmp/lab-work/artifacts/registry-0.2.0 --project /tmp/lab-work/reg02 law publish /tmp/lab-work/artifacts/registry-0.2.0 --registry lab=/tmp/lab-work/registry ``` ```text labparcels.registry@0.2.0 → /tmp/lab-work/artifacts/registry-0.2.0: contentHash sha256:fc69df17896dd8c60a4a4889e2313fd3228b234444bf0e36d98a94372ab96ce2, worldHash sha256:b3056c550cfaf9c58fa84befda4557d3b6c5020fdfc8c324086335343998e597, 3 files labparcels.registry@0.2.0 → lab (/tmp/lab-work/registry): contentHash sha256:fc69df17896dd8c60a4a4889e2313fd3228b234444bf0e36d98a94372ab96ce2, worldHash sha256:b3056c550cfaf9c58fa84befda4557d3b6c5020fdfc8c324086335343998e597 versions labparcels.registry: 0.1.0, 0.2.0 changed: p/labparcels.registry/0.2.0/package.lawir.json changed: p/labparcels.registry/0.2.0/world.lawir.json changed: p/labparcels.registry/0.2.0.json ``` Currency now flags the new revision and exits 1; the lock stays untouched: ```shell law outdated --project fixtures/parcels-fees --registry lab=/tmp/lab-work/registry ``` ```text lab ← /tmp/lab-work/registry (--registry) labparcels.iface@0.1.0 [lab]: up to date labparcels.registry@0.1.0 [lab]: published 0.2.0 ``` Move a scratch copy of the fees consumer across. Copy first, which is silent, then preview: ```shell cp -r fixtures/parcels-fees /tmp/lab-work/fees-upd law update 'labparcels.registry@0.2.0' --project /tmp/lab-work/fees-upd --registry lab=/tmp/lab-work/registry --dry-run ``` ```text lab ← /tmp/lab-work/registry (--registry) --dry-run: staged and verified, no file changed ~ labparcels.registry 0.1.0 -> 0.2.0 changed: .law/transport.json changed: deps/labparcels.registry.lawir.json changed: law.lock changed: law.toml changed: package.law ``` Then run the same command without the preview flag: ```shell law update 'labparcels.registry@0.2.0' --project /tmp/lab-work/fees-upd --registry lab=/tmp/lab-work/registry ``` ```text lab ← /tmp/lab-work/registry (--registry) ~ labparcels.registry 0.1.0 -> 0.2.0 changed: .law/transport.json changed: deps/labparcels.registry.lawir.json changed: law.lock changed: law.toml changed: package.law ``` The update rewrites the import line to the new version alongside the manifest, the lock, and the pinned bytes. The consumer scenarios still pass five for five, and currency reports both pins up to date with exit 0: ```shell law test /tmp/lab-work/fees-upd | tail -n 1 law outdated --project /tmp/lab-work/fees-upd --registry lab=/tmp/lab-work/registry ``` ```text total: 5 checked, 5 passed, 0 failed, 0 not run; code 0 ``` ```text lab ← /tmp/lab-work/registry (--registry) labparcels.iface@0.1.0 [lab]: up to date labparcels.registry@0.2.0 [lab]: up to date ``` Two refusals close the exercise. Asking for a revision that was never published: ```shell law update 'labparcels.registry@0.9.9' --project /tmp/lab-work/fees-upd --registry lab=/tmp/lab-work/registry ``` ```text law: REFUSAL: registry lab, p/labparcels.registry/0.9.9.json: No such file or directory (os error 2) ``` And editing one fragment line by hand on another scratch copy, which the pinning check catches. The copy and the one-word edit are silent; the check and the diff answer. Start from the bundle root as above; the two generator calls need the checkout (`gen` is not in the public composition), so they run in a subshell there: ```shell cp -r fixtures/parcels-registry /tmp/lab-work/regdrift : "${ARXO_CHECKOUT:?absolute path to the full checkout}" perl -pi -e 's/registers nothing\."""/registers nothing much."""/' /tmp/lab-work/regdrift/sources.law (cd "$ARXO_CHECKOUT" && ./law gen pinning /tmp/lab-work/regdrift) (cd "$ARXO_CHECKOUT" && ./law gen pinning /tmp/lab-work/regdrift --diff) ``` ```text ✗ pinning.toml → sources.law [en-US] (2 articles) ``` ```text ✗ pinning.toml → sources.law [en-US] (2 articles) --- sources.law +++ pinning.toml @@ -7,3 +7,3 @@ -recorded for it. A holding without a recorded kind registers nothing much."""; +recorded for it. A holding without a recorded kind registers nothing."""; ``` ## Stage A exercise Pack the original five states plus the fee revision into the stage directory: ```shell mkdir -p /tmp/lab-work/stage-a/artifacts /tmp/lab-work/stage-a/answers law pack --out /tmp/lab-work/stage-a/artifacts/iface --project fixtures/parcels-iface law pack --out /tmp/lab-work/stage-a/artifacts/registry --project fixtures/parcels-registry law pack --out /tmp/lab-work/stage-a/artifacts/fees --project fixtures/parcels-fees law pack --out /tmp/lab-work/stage-a/artifacts/appeals --project fixtures/parcels-appeals law pack --out /tmp/lab-work/stage-a/artifacts/case1 --project fixtures/parcels-case1 law pack --out /tmp/lab-work/stage-a/artifacts/fees-0.3.0 --project fixtures/parcels-fees-0.3.0 ``` ```text labparcels.iface@0.1.0 → /tmp/lab-work/stage-a/artifacts/iface: contentHash sha256:23b7a38c3f80dc22015fe983e6ae21083e4d52d9ef1309a5e36d964cf0a31ac2, worldHash sha256:23b7a38c3f80dc22015fe983e6ae21083e4d52d9ef1309a5e36d964cf0a31ac2, 3 files labparcels.registry@0.1.0 → /tmp/lab-work/stage-a/artifacts/registry: contentHash sha256:15b5bd7fe6f4260b5e2f94e9c8ba5af53150e36c55365b3d463e5bc34215368f, worldHash sha256:13ef321e7bf4e5e44b45f2142e1f000e2ba4ffbf749cb3694041993bb6346ef2, 3 files labparcels.fees@0.2.0 → /tmp/lab-work/stage-a/artifacts/fees: contentHash sha256:dfe81269bfe070987ada69e4c2545e9c31a755aa1600be72a8242a00c30dbde4, worldHash sha256:056a48336aba96920988682a4a72e723c35a9d177f094d549f79df1739322b7a, 3 files labparcels.appeals@0.1.0 → /tmp/lab-work/stage-a/artifacts/appeals: contentHash sha256:92860bd5cd0ac02edbe666965d8430fb360dc5f938fcabaee4d83f1f95b7df6e, worldHash sha256:866374f2e79343b9cef623feeef6961574b32a6fce02c2533d486eb97fc1012e, 3 files labparcels.case1@0.1.0 → /tmp/lab-work/stage-a/artifacts/case1: contentHash sha256:14ae7edbf58225f3fdf1cc7b5f21cb14ac33fb223795a2834d4c8d765b6f0cdc, worldHash sha256:59059bde677910196f9d3533e782716e9cd776e21e2b873119a3c35d191bce10, 3 files labparcels.fees@0.3.0 → /tmp/lab-work/stage-a/artifacts/fees-0.3.0: contentHash sha256:a7bdcc8144572aef2a00f0d833db3007edf9c4818a79fafbf4a97576c75e06f8, worldHash sha256:3ba271665819555171ba1f980bae9f5e48548e43f4aaed8932f999d2e0749067, 3 files ``` Publish the six into the stage registry and copy the case aside: ```shell law publish /tmp/lab-work/stage-a/artifacts/iface --registry lab=/tmp/lab-work/stage-a/registry law publish /tmp/lab-work/stage-a/artifacts/registry --registry lab=/tmp/lab-work/stage-a/registry law publish /tmp/lab-work/stage-a/artifacts/fees --registry lab=/tmp/lab-work/stage-a/registry law publish /tmp/lab-work/stage-a/artifacts/appeals --registry lab=/tmp/lab-work/stage-a/registry law publish /tmp/lab-work/stage-a/artifacts/case1 --registry lab=/tmp/lab-work/stage-a/registry law publish /tmp/lab-work/stage-a/artifacts/fees-0.3.0 --registry lab=/tmp/lab-work/stage-a/registry cp -r fixtures/parcels-case1 /tmp/lab-work/stage-a/case1 ``` ```text registry lab created: /tmp/lab-work/stage-a/registry labparcels.iface@0.1.0 → lab (/tmp/lab-work/stage-a/registry): contentHash sha256:23b7a38c3f80dc22015fe983e6ae21083e4d52d9ef1309a5e36d964cf0a31ac2, worldHash sha256:23b7a38c3f80dc22015fe983e6ae21083e4d52d9ef1309a5e36d964cf0a31ac2 versions labparcels.iface: 0.1.0 changed: p/labparcels.iface/0.1.0/package.lawir.json changed: p/labparcels.iface/0.1.0/world.lawir.json changed: p/labparcels.iface/0.1.0.json labparcels.registry@0.1.0 → lab (/tmp/lab-work/stage-a/registry): contentHash sha256:15b5bd7fe6f4260b5e2f94e9c8ba5af53150e36c55365b3d463e5bc34215368f, worldHash sha256:13ef321e7bf4e5e44b45f2142e1f000e2ba4ffbf749cb3694041993bb6346ef2 versions labparcels.registry: 0.1.0 changed: p/labparcels.registry/0.1.0/package.lawir.json changed: p/labparcels.registry/0.1.0/world.lawir.json changed: p/labparcels.registry/0.1.0.json labparcels.fees@0.2.0 → lab (/tmp/lab-work/stage-a/registry): contentHash sha256:dfe81269bfe070987ada69e4c2545e9c31a755aa1600be72a8242a00c30dbde4, worldHash sha256:056a48336aba96920988682a4a72e723c35a9d177f094d549f79df1739322b7a versions labparcels.fees: 0.2.0 changed: p/labparcels.fees/0.2.0/package.lawir.json changed: p/labparcels.fees/0.2.0/world.lawir.json changed: p/labparcels.fees/0.2.0.json labparcels.appeals@0.1.0 → lab (/tmp/lab-work/stage-a/registry): contentHash sha256:92860bd5cd0ac02edbe666965d8430fb360dc5f938fcabaee4d83f1f95b7df6e, worldHash sha256:866374f2e79343b9cef623feeef6961574b32a6fce02c2533d486eb97fc1012e versions labparcels.appeals: 0.1.0 changed: p/labparcels.appeals/0.1.0/package.lawir.json changed: p/labparcels.appeals/0.1.0/world.lawir.json changed: p/labparcels.appeals/0.1.0.json labparcels.case1@0.1.0 → lab (/tmp/lab-work/stage-a/registry): contentHash sha256:14ae7edbf58225f3fdf1cc7b5f21cb14ac33fb223795a2834d4c8d765b6f0cdc, worldHash sha256:59059bde677910196f9d3533e782716e9cd776e21e2b873119a3c35d191bce10 versions labparcels.case1: 0.1.0 changed: p/labparcels.case1/0.1.0/package.lawir.json changed: p/labparcels.case1/0.1.0/world.lawir.json changed: p/labparcels.case1/0.1.0.json labparcels.fees@0.3.0 → lab (/tmp/lab-work/stage-a/registry): contentHash sha256:a7bdcc8144572aef2a00f0d833db3007edf9c4818a79fafbf4a97576c75e06f8, worldHash sha256:3ba271665819555171ba1f980bae9f5e48548e43f4aaed8932f999d2e0749067 versions labparcels.fees: 0.2.0, 0.3.0 changed: p/labparcels.fees/0.3.0/package.lawir.json changed: p/labparcels.fees/0.3.0/world.lawir.json changed: p/labparcels.fees/0.3.0.json ``` Save the three old answers. The full texts match the answers recorded earlier; only the footers are shown: ```shell law ask /tmp/lab-work/stage-a/case1 --case ParcelTransfer --query-json /tmp/lab-work/stage-a/case1/queries/fee-answered.json --format text --out /tmp/lab-work/stage-a/answers/fee-answered | tail -n 1 law ask /tmp/lab-work/stage-a/case1 --case ParcelTransfer --query-json /tmp/lab-work/stage-a/case1/queries/transfer-answered.json --format text --out /tmp/lab-work/stage-a/answers/transfer-answered | tail -n 1 law ask /tmp/lab-work/stage-a/case1 --case ParcelTransfer --query-json /tmp/lab-work/stage-a/case1/queries/appeal-answered.json --format text --out /tmp/lab-work/stage-a/answers/appeal-answered | tail -n 1 ``` ```text *Вопрос `urn:law:lab:parcels:case1#case/ParcelTransfer/query/fee-answered` · результат `urn:result:case1#case/ParcelTransfer/query/fee-answered` · resultHash `sha256:dc3120593dd12d014b6fb50adb5a05403b0fbb43b6686d02ff4dcbfcf693c677` · программа `sha256:f219f1832a4945e55f3227f424ad69df7d4cab5c8691c6dd37e8ce7067eab182` · вербализация law.verb.ru@0.39.0 · язык ru-KZ · подробность: полное дерево* *Вопрос `urn:law:lab:parcels:case1#case/ParcelTransfer/query/transfer-answered` · результат `urn:result:case1#case/ParcelTransfer/query/transfer-answered` · resultHash `sha256:8c5deca4fb4bcf6fcbdda27f6715aba5807de7942803db573213f05b7ff000e7` · программа `sha256:f219f1832a4945e55f3227f424ad69df7d4cab5c8691c6dd37e8ce7067eab182` · вербализация law.verb.ru@0.39.0 · язык ru-KZ · подробность: полное дерево* *Вопрос `urn:law:lab:parcels:case1#case/ParcelTransfer/query/appeal-answered` · результат `urn:result:case1#case/ParcelTransfer/query/appeal-answered` · resultHash `sha256:eb9b1cf945f951ac18d09abb8eb6ece82566f0f37c4b8fa6da0e36becf449da1` · программа `sha256:f219f1832a4945e55f3227f424ad69df7d4cab5c8691c6dd37e8ce7067eab182` · вербализация law.verb.ru@0.39.0 · язык ru-KZ · подробность: полное дерево* ``` Replay the saved fee answer on its saved inputs. The recomputed hash matches the saved footer exactly: ```shell law eval /tmp/lab-work/stage-a/answers/fee-answered | python3 -c "import json,sys; d=json.load(sys.stdin); print(d['resultHash'], d['results'][0]['truthStatus'], d['results'][0]['evaluationStatus'])" ``` ```text sha256:dc3120593dd12d014b6fb50adb5a05403b0fbb43b6686d02ff4dcbfcf693c677 TRUE_ONLY COMPUTED ``` Run both consumers plus the scratch case before the move. Every test passes, which fixes the baseline the predictions are written against: ```shell law test fixtures/parcels-fees-0.3.0 | tail -n 1 law test fixtures/parcels-appeals | tail -n 1 law test /tmp/lab-work/stage-a/case1 | tail -n 1 ``` ```text total: 5 checked, 5 passed, 0 failed, 0 not run; code 0 total: 3 checked, 3 passed, 0 failed, 0 not run; code 0 total: 4 checked, 4 passed, 0 failed, 0 not run; code 0 ``` Move the scratch case across, preview first: ```shell law update 'labparcels.fees@0.3.0' --project /tmp/lab-work/stage-a/case1 --registry lab=/tmp/lab-work/stage-a/registry --dry-run law update 'labparcels.fees@0.3.0' --project /tmp/lab-work/stage-a/case1 --registry lab=/tmp/lab-work/stage-a/registry ``` ```text lab ← /tmp/lab-work/stage-a/registry (--registry) --dry-run: staged and verified, no file changed ~ labparcels.fees 0.2.0 -> 0.3.0 changed: .law/transport.json changed: deps/labparcels.fees.lawir.json changed: law.lock changed: law.toml changed: package.law lab ← /tmp/lab-work/stage-a/registry (--registry) ~ labparcels.fees 0.2.0 -> 0.3.0 changed: .law/transport.json changed: deps/labparcels.fees.lawir.json changed: law.lock changed: law.toml changed: package.law ``` The case run breaks exactly where predicted: the fee expectation still names the old amount, and the other three scenarios hold: ```shell law test /tmp/lab-work/stage-a/case1 ``` ```text law test labparcels.case1: world labparcels.case1, labparcels.appeals, labparcels.fees, labparcels.iface, labparcels.registry FAIL [labparcels.case1#authored] tests/01-worked-parcel.lawtest / urn:lab:parcels:case1:fee truth_status == TRUE_ONLY: in the document NEITHER ok [labparcels.case1#authored] tests/01-worked-parcel.lawtest / urn:lab:parcels:case1:transfer ok [labparcels.case1#authored] tests/01-worked-parcel.lawtest / urn:lab:parcels:case1:appeal ok [labparcels.case1#authored] tests/01-worked-parcel.lawtest / urn:lab:parcels:case1:wrong-fee total: 4 checked, 3 passed, 1 failed, 0 not run; code 1 ``` The four verdicts after the move. The old amount goes silent. The `grep` pattern keeps the Russian lines `Установлено` (established), `Не установлено` (not established), and `Вычисление` (evaluation), plus the hash line; the [table under Answers](#answers) translates the rest: ```shell law ask /tmp/lab-work/stage-a/case1 --case ParcelTransfer --query-json /tmp/lab-work/stage-a/case1/queries/fee-answered.json --format text | grep -E '^(Установлено|Не установлено|Вычисление)|resultHash' ``` ```text Установлено ли, что «fee_due» (parcel: `p1`, сумма: 100)? Вычисление завершено. Не установлено ни что «fee_due» (parcel: `p1`, сумма: 100), ни обратное. Это не утверждение ложности и не заключение о молчании права: в модели нет вывода ни в одну сторону. *Вопрос `urn:law:lab:parcels:case1#case/ParcelTransfer/query/fee-answered` · результат `urn:result:case1#case/ParcelTransfer/query/fee-answered` · resultHash `sha256:1f964362f7df39c21f9648c79a3873a38bc1cb98647bc83d65fdba4af9f7eb92` · программа `sha256:4d39c555f907eed6d9db404a4b9e60b970cd990b1d60267cd2be60c585b3558b` · вербализация law.verb.ru@0.39.0 · язык ru-KZ · подробность: полное дерево* ``` The new amount is established, asked in the inline form, which spells the amount as a plain integer: ```shell law ask /tmp/lab-work/stage-a/case1 --case ParcelTransfer --query 'evaluate truth(labparcels.fees::fee_due(entity_ref("urn:lab:parcel:p1"), 120));' --query-id fee-120 --format text | grep -E '^(Установлено|Не установлено|Вычисление)|resultHash' ``` ```text Установлено ли, что «fee_due» (parcel: `p1`, сумма: 120)? Вычисление завершено. Установлено, что «fee_due» (parcel: `p1`, сумма: 120); обратное не установлено. *Вопрос `urn:law:lab:parcels:case1#case/ParcelTransfer/query/fee-120` · результат `urn:result:case1#case/ParcelTransfer/query/fee-120` · resultHash `sha256:f4c3cafa5b2ae77b709300d7f6f720b9e388b95b189d538b9237841c58fa3e21` · программа `sha256:4d39c555f907eed6d9db404a4b9e60b970cd990b1d60267cd2be60c585b3558b` · вербализация law.verb.ru@0.39.0 · язык ru-KZ · подробность: полное дерево* ``` The other two verdicts stand, with new hashes behind the changed program bytes: ```shell law ask /tmp/lab-work/stage-a/case1 --case ParcelTransfer --query-json /tmp/lab-work/stage-a/case1/queries/transfer-answered.json --format text | grep -E '^(Установлено|Не установлено)|resultHash' law ask /tmp/lab-work/stage-a/case1 --case ParcelTransfer --query-json /tmp/lab-work/stage-a/case1/queries/appeal-answered.json --format text | grep -E '^(Установлено|Не установлено)|resultHash' ``` ```text Установлено ли, что «transfer_granted» (parcel: `p1`, from: `amy`, to: `bob`)? Установлено, что «transfer_granted» (parcel: `p1`, from: `amy`, to: `bob`); обратное не установлено. *Вопрос `urn:law:lab:parcels:case1#case/ParcelTransfer/query/transfer-answered` · результат `urn:result:case1#case/ParcelTransfer/query/transfer-answered` · resultHash `sha256:756b93ce490b5cf69d01dffabcab1b4f1b92798b2e53a3fab7ea2039b0ecce80` · программа `sha256:4d39c555f907eed6d9db404a4b9e60b970cd990b1d60267cd2be60c585b3558b` · вербализация law.verb.ru@0.39.0 · язык ru-KZ · подробность: полное дерево* Установлено ли, что «appeal_timely» (parcel: `p1`)? Установлено, что «appeal_timely» (parcel: `p1`); обратное не установлено. *Вопрос `urn:law:lab:parcels:case1#case/ParcelTransfer/query/appeal-answered` · результат `urn:result:case1#case/ParcelTransfer/query/appeal-answered` · resultHash `sha256:2deb58533df3f1c2a59067a8e0e2e7cdc54e3ee6469df805a99b2d5dfeee3b30` · программа `sha256:4d39c555f907eed6d9db404a4b9e60b970cd990b1d60267cd2be60c585b3558b` · вербализация law.verb.ru@0.39.0 · язык ru-KZ · подробность: полное дерево* ``` Move the stale expectation to the new amount and rerun until every test passes. The shipped fee revision already carries the same move in its own wrong-amount scenario: ```law fixture="parcels-fees-0.3.0/tests/05-fee-wrong-amount.lawtest" language "law.core" version "0.2"; package labparcels.fees version "0.3.0"; namespace "urn:law:lab:parcels:fees"; // A residential parcel owes 120, so the old 100 for it is not established. test "urn:lab:parcels:fees:wrong-amount" { given { context { legal_time @2026-01-15; } assert "holding": labparcels.iface::owns(entity_ref("urn:lab:owner:amy"), entity_ref("urn:lab:parcel:p1")) { origin case_input; } assert "kind": labparcels.registry::kind_of(entity_ref("urn:lab:parcel:p1"), labparcels.iface::residential) { origin case_input; } } evaluate truth(fee_due(entity_ref("urn:lab:parcel:p1"), 100)); expect result_kind == PROPOSITION; expect truth_status == NEITHER; } ``` ```shell perl -pi -e 's/fee_due\(entity_ref\("urn:lab:parcel:p1"\), 100\)/fee_due(entity_ref("urn:lab:parcel:p1"), 120)/' /tmp/lab-work/stage-a/case1/tests/01-worked-parcel.lawtest grep -n "evaluate" /tmp/lab-work/stage-a/case1/tests/01-worked-parcel.lawtest law test /tmp/lab-work/stage-a/case1 | tail -n 1 ``` ```text 27: evaluate truth(labparcels.fees::fee_due(entity_ref("urn:lab:parcel:p1"), 120)); 45: evaluate truth(labparcels.registry::transfer_granted(entity_ref("urn:lab:parcel:p1"), entity_ref("urn:lab:owner:amy"), entity_ref("urn:lab:owner:bob"))); 66: evaluate truth(labparcels.appeals::appeal_timely(entity_ref("urn:lab:parcel:p1"))); 81: evaluate truth(labparcels.fees::fee_due(entity_ref("urn:lab:parcel:p1"), 250)); total: 4 checked, 4 passed, 0 failed, 0 not run; code 0 ``` Close the loop after the update: replay the saved old answer and ask the fresh question side by side. History is preserved exactly when the replay reproduces the old hash while the live world answers the new amount: ```shell law eval /tmp/lab-work/stage-a/answers/fee-answered | python3 -c "import json,sys; d=json.load(sys.stdin); print(d['resultHash'], d['results'][0]['truthStatus'], d['results'][0]['evaluationStatus'])" law ask /tmp/lab-work/stage-a/case1 --case ParcelTransfer --query 'evaluate truth(labparcels.fees::fee_due(entity_ref("urn:lab:parcel:p1"), 120));' --query-id fee-120 --format text | tail -n 1 ``` ```text sha256:dc3120593dd12d014b6fb50adb5a05403b0fbb43b6686d02ff4dcbfcf693c677 TRUE_ONLY COMPUTED *Вопрос `urn:law:lab:parcels:case1#case/ParcelTransfer/query/fee-120` · результат `urn:result:case1#case/ParcelTransfer/query/fee-120` · resultHash `sha256:f4c3cafa5b2ae77b709300d7f6f720b9e388b95b189d538b9237841c58fa3e21` · программа `sha256:4d39c555f907eed6d9db404a4b9e60b970cd990b1d60267cd2be60c585b3558b` · вербализация law.verb.ru@0.39.0 · язык ru-KZ · подробность: полное дерево* ``` The replayed `dc312059…` equals the pre-update footer byte for byte; the fresh `f4c3cafa…` answers the updated world. One command proves the past is intact, the other that the present moved. ## Stage B exercise Pack the original five states plus the four renamed revisions: ```shell mkdir -p /tmp/lab-work/stage-b/artifacts law pack --out /tmp/lab-work/stage-b/artifacts/iface --project fixtures/parcels-iface law pack --out /tmp/lab-work/stage-b/artifacts/registry --project fixtures/parcels-registry law pack --out /tmp/lab-work/stage-b/artifacts/fees --project fixtures/parcels-fees law pack --out /tmp/lab-work/stage-b/artifacts/appeals --project fixtures/parcels-appeals law pack --out /tmp/lab-work/stage-b/artifacts/case1 --project fixtures/parcels-case1 law pack --out /tmp/lab-work/stage-b/artifacts/iface-0.2.0 --project fixtures/parcels-iface-0.2.0 law pack --out /tmp/lab-work/stage-b/artifacts/registry-0.3.0 --project fixtures/parcels-registry-0.3.0 law pack --out /tmp/lab-work/stage-b/artifacts/fees-0.4.0 --project fixtures/parcels-fees-0.4.0 law pack --out /tmp/lab-work/stage-b/artifacts/appeals-0.2.0 --project fixtures/parcels-appeals-0.2.0 ``` ```text labparcels.iface@0.1.0 → /tmp/lab-work/stage-b/artifacts/iface: contentHash sha256:23b7a38c3f80dc22015fe983e6ae21083e4d52d9ef1309a5e36d964cf0a31ac2, worldHash sha256:23b7a38c3f80dc22015fe983e6ae21083e4d52d9ef1309a5e36d964cf0a31ac2, 3 files labparcels.registry@0.1.0 → /tmp/lab-work/stage-b/artifacts/registry: contentHash sha256:15b5bd7fe6f4260b5e2f94e9c8ba5af53150e36c55365b3d463e5bc34215368f, worldHash sha256:13ef321e7bf4e5e44b45f2142e1f000e2ba4ffbf749cb3694041993bb6346ef2, 3 files labparcels.fees@0.2.0 → /tmp/lab-work/stage-b/artifacts/fees: contentHash sha256:dfe81269bfe070987ada69e4c2545e9c31a755aa1600be72a8242a00c30dbde4, worldHash sha256:056a48336aba96920988682a4a72e723c35a9d177f094d549f79df1739322b7a, 3 files labparcels.appeals@0.1.0 → /tmp/lab-work/stage-b/artifacts/appeals: contentHash sha256:92860bd5cd0ac02edbe666965d8430fb360dc5f938fcabaee4d83f1f95b7df6e, worldHash sha256:866374f2e79343b9cef623feeef6961574b32a6fce02c2533d486eb97fc1012e, 3 files labparcels.case1@0.1.0 → /tmp/lab-work/stage-b/artifacts/case1: contentHash sha256:14ae7edbf58225f3fdf1cc7b5f21cb14ac33fb223795a2834d4c8d765b6f0cdc, worldHash sha256:59059bde677910196f9d3533e782716e9cd776e21e2b873119a3c35d191bce10, 3 files labparcels.iface@0.2.0 → /tmp/lab-work/stage-b/artifacts/iface-0.2.0: contentHash sha256:1c5f687074bd1fbf9424aff0cbd114fa6fac030e6c452c30a9a0d6a33c06f7fe, worldHash sha256:1c5f687074bd1fbf9424aff0cbd114fa6fac030e6c452c30a9a0d6a33c06f7fe, 3 files labparcels.registry@0.3.0 → /tmp/lab-work/stage-b/artifacts/registry-0.3.0: contentHash sha256:a0e9dfd1127f95659d921c49b53f04b78b0aea80aee74ee03f9e6141ca2824b5, worldHash sha256:ab2e0837c94bb2f8dd526e8251fafea3df241b09517433eb2c5b4e6bbbf5410a, 3 files labparcels.fees@0.4.0 → /tmp/lab-work/stage-b/artifacts/fees-0.4.0: contentHash sha256:2e3998a465a47d6dadfcc1a440443d3fd13c49ade4fcdb09e95930aa1e493d3f, worldHash sha256:5fb87994153eb7af496c6fe86e18f4ccc0df1fa6f613f0e4cb5c4d49d5dadb9e, 3 files labparcels.appeals@0.2.0 → /tmp/lab-work/stage-b/artifacts/appeals-0.2.0: contentHash sha256:674f43e0462c2e2637c1a7c0e6855133b4dab24a1d522754f028057d49502e22, worldHash sha256:d268b848eff7519bb4a37700e6bdd99c5117c998b4cc93f6a5153cfbac025073, 3 files ``` Publish the nine into the stage registry and copy the work areas aside. The copies are silent: ```shell law publish /tmp/lab-work/stage-b/artifacts/iface --registry lab=/tmp/lab-work/stage-b/registry law publish /tmp/lab-work/stage-b/artifacts/registry --registry lab=/tmp/lab-work/stage-b/registry law publish /tmp/lab-work/stage-b/artifacts/fees --registry lab=/tmp/lab-work/stage-b/registry law publish /tmp/lab-work/stage-b/artifacts/appeals --registry lab=/tmp/lab-work/stage-b/registry law publish /tmp/lab-work/stage-b/artifacts/case1 --registry lab=/tmp/lab-work/stage-b/registry law publish /tmp/lab-work/stage-b/artifacts/iface-0.2.0 --registry lab=/tmp/lab-work/stage-b/registry law publish /tmp/lab-work/stage-b/artifacts/registry-0.3.0 --registry lab=/tmp/lab-work/stage-b/registry law publish /tmp/lab-work/stage-b/artifacts/fees-0.4.0 --registry lab=/tmp/lab-work/stage-b/registry law publish /tmp/lab-work/stage-b/artifacts/appeals-0.2.0 --registry lab=/tmp/lab-work/stage-b/registry cp -r fixtures/parcels-registry /tmp/lab-work/stage-b/reg-old cp -r fixtures/parcels-case1 /tmp/lab-work/stage-b/case1-holds cp -r fixtures/parcels-fees /tmp/lab-work/stage-b/fees-conflict ``` ```text registry lab created: /tmp/lab-work/stage-b/registry labparcels.iface@0.1.0 → lab (/tmp/lab-work/stage-b/registry): contentHash sha256:23b7a38c3f80dc22015fe983e6ae21083e4d52d9ef1309a5e36d964cf0a31ac2, worldHash sha256:23b7a38c3f80dc22015fe983e6ae21083e4d52d9ef1309a5e36d964cf0a31ac2 versions labparcels.iface: 0.1.0 changed: p/labparcels.iface/0.1.0/package.lawir.json changed: p/labparcels.iface/0.1.0/world.lawir.json changed: p/labparcels.iface/0.1.0.json labparcels.registry@0.1.0 → lab (/tmp/lab-work/stage-b/registry): contentHash sha256:15b5bd7fe6f4260b5e2f94e9c8ba5af53150e36c55365b3d463e5bc34215368f, worldHash sha256:13ef321e7bf4e5e44b45f2142e1f000e2ba4ffbf749cb3694041993bb6346ef2 versions labparcels.registry: 0.1.0 changed: p/labparcels.registry/0.1.0/package.lawir.json changed: p/labparcels.registry/0.1.0/world.lawir.json changed: p/labparcels.registry/0.1.0.json labparcels.fees@0.2.0 → lab (/tmp/lab-work/stage-b/registry): contentHash sha256:dfe81269bfe070987ada69e4c2545e9c31a755aa1600be72a8242a00c30dbde4, worldHash sha256:056a48336aba96920988682a4a72e723c35a9d177f094d549f79df1739322b7a versions labparcels.fees: 0.2.0 changed: p/labparcels.fees/0.2.0/package.lawir.json changed: p/labparcels.fees/0.2.0/world.lawir.json changed: p/labparcels.fees/0.2.0.json labparcels.appeals@0.1.0 → lab (/tmp/lab-work/stage-b/registry): contentHash sha256:92860bd5cd0ac02edbe666965d8430fb360dc5f938fcabaee4d83f1f95b7df6e, worldHash sha256:866374f2e79343b9cef623feeef6961574b32a6fce02c2533d486eb97fc1012e versions labparcels.appeals: 0.1.0 changed: p/labparcels.appeals/0.1.0/package.lawir.json changed: p/labparcels.appeals/0.1.0/world.lawir.json changed: p/labparcels.appeals/0.1.0.json labparcels.case1@0.1.0 → lab (/tmp/lab-work/stage-b/registry): contentHash sha256:14ae7edbf58225f3fdf1cc7b5f21cb14ac33fb223795a2834d4c8d765b6f0cdc, worldHash sha256:59059bde677910196f9d3533e782716e9cd776e21e2b873119a3c35d191bce10 versions labparcels.case1: 0.1.0 changed: p/labparcels.case1/0.1.0/package.lawir.json changed: p/labparcels.case1/0.1.0/world.lawir.json changed: p/labparcels.case1/0.1.0.json labparcels.iface@0.2.0 → lab (/tmp/lab-work/stage-b/registry): contentHash sha256:1c5f687074bd1fbf9424aff0cbd114fa6fac030e6c452c30a9a0d6a33c06f7fe, worldHash sha256:1c5f687074bd1fbf9424aff0cbd114fa6fac030e6c452c30a9a0d6a33c06f7fe versions labparcels.iface: 0.1.0, 0.2.0 changed: p/labparcels.iface/0.2.0/package.lawir.json changed: p/labparcels.iface/0.2.0/world.lawir.json changed: p/labparcels.iface/0.2.0.json labparcels.registry@0.3.0 → lab (/tmp/lab-work/stage-b/registry): contentHash sha256:a0e9dfd1127f95659d921c49b53f04b78b0aea80aee74ee03f9e6141ca2824b5, worldHash sha256:ab2e0837c94bb2f8dd526e8251fafea3df241b09517433eb2c5b4e6bbbf5410a versions labparcels.registry: 0.1.0, 0.3.0 changed: p/labparcels.registry/0.3.0/package.lawir.json changed: p/labparcels.registry/0.3.0/world.lawir.json changed: p/labparcels.registry/0.3.0.json labparcels.fees@0.4.0 → lab (/tmp/lab-work/stage-b/registry): contentHash sha256:2e3998a465a47d6dadfcc1a440443d3fd13c49ade4fcdb09e95930aa1e493d3f, worldHash sha256:5fb87994153eb7af496c6fe86e18f4ccc0df1fa6f613f0e4cb5c4d49d5dadb9e versions labparcels.fees: 0.2.0, 0.4.0 changed: p/labparcels.fees/0.4.0/package.lawir.json changed: p/labparcels.fees/0.4.0/world.lawir.json changed: p/labparcels.fees/0.4.0.json labparcels.appeals@0.2.0 → lab (/tmp/lab-work/stage-b/registry): contentHash sha256:674f43e0462c2e2637c1a7c0e6855133b4dab24a1d522754f028057d49502e22, worldHash sha256:d268b848eff7519bb4a37700e6bdd99c5117c998b4cc93f6a5153cfbac025073 versions labparcels.appeals: 0.1.0, 0.2.0 changed: p/labparcels.appeals/0.2.0/package.lawir.json changed: p/labparcels.appeals/0.2.0/world.lawir.json changed: p/labparcels.appeals/0.2.0.json ``` The break. Moving the unmigrated act under the renamed vocabulary is refused with a nonzero exit, and the pins stay untouched. The refusal names the missing word at both rules that read it and lists the new word among the exports: ```shell law update 'labparcels.iface@0.2.0' --project /tmp/lab-work/stage-b/reg-old --registry lab=/tmp/lab-work/stage-b/registry --dry-run grep -n "labparcels.iface" /tmp/lab-work/stage-b/reg-old/law.toml ``` ```text law: REFUSAL: prepared package fails check: /tmp/lab-work/stage-b/reg-old/.law/verify/package.law:38:10: error LDC-E1105: labparcels.iface::owns: symbol is not exported by the package (§24: cross-package references target only `pub` declarations; exported: Owner, Parcel, ParcelKind, commercial, garden, holds, residential) /tmp/lab-work/stage-b/reg-old/.law/verify/package.law:47:28: error LDC-E1105: labparcels.iface::owns: symbol is not exported by the package (§24: cross-package references target only `pub` declarations; exported: Owner, Parcel, ParcelKind, commercial, garden, holds, residential) 19:world = ["labparcels.registry", "labparcels.iface"] 25:"labparcels.iface" = "0.1.0" ``` The second refusal: moving one of two coupled pins alone is a version conflict, so the migration below rewires pins together: ```shell law update 'labparcels.iface@0.2.0' --project /tmp/lab-work/stage-b/fees-conflict --registry lab=/tmp/lab-work/stage-b/registry --dry-run ``` ```text law: REFUSAL LPK-E0401: package labparcels.iface version conflict: 0.1.0 vs 0.2.0 — consumers: labparcels.registry → labparcels.iface@0.1.0; labparcels.fees → labparcels.iface@0.2.0 → update one consumer with `law update NAME` to a shared version ``` The migration. Rename the holding link in the scratch case file and its scenarios. The shipped act revision shows the same move in its own rules: ```law fixture="parcels-registry-0.3.0/package.law" @source(PARCEL_RULE_1) rule RegistrationComplete strict { for p: Parcel; for o: Owner; for k: ParcelKind; when labparcels.iface::holds(o, p) and kind_of(p, k); then registered(p); } ``` ```shell perl -pi -e 's/labparcels\.iface::owns\(/labparcels.iface::holds(/g' /tmp/lab-work/stage-b/case1-holds/cases/parcel-transfer.lawcase /tmp/lab-work/stage-b/case1-holds/tests/01-worked-parcel.lawtest grep -c "holds" /tmp/lab-work/stage-b/case1-holds/cases/parcel-transfer.lawcase /tmp/lab-work/stage-b/case1-holds/tests/01-worked-parcel.lawtest ``` ```text /tmp/lab-work/stage-b/case1-holds/cases/parcel-transfer.lawcase:1 /tmp/lab-work/stage-b/case1-holds/tests/01-worked-parcel.lawtest:4 ``` Strip the four pins to a bare header, keeping the saved body aside. The strip commands are silent; the two readings confirm the bare state: ```shell cp /tmp/lab-work/stage-b/case1-holds/package.law /tmp/lab-work/stage-b/case1-body.law python3 -c "t=open('/tmp/lab-work/stage-b/case1-holds/law.toml').read(); t=t.split('[dependencies]')[0].rstrip()+'\n'; open('/tmp/lab-work/stage-b/case1-holds/law.toml','w').write(t); h=open('/tmp/lab-work/stage-b/case1-holds/package.law').read().split('\n'); open('/tmp/lab-work/stage-b/case1-holds/package.law','w').write('\n'.join(h[:3])+'\n')" rm -rf /tmp/lab-work/stage-b/case1-holds/deps /tmp/lab-work/stage-b/case1-holds/law.lock /tmp/lab-work/stage-b/case1-holds/.law cat /tmp/lab-work/stage-b/case1-holds/package.law tail -n 3 /tmp/lab-work/stage-b/case1-holds/law.toml ``` ```law language "law.core" version "0.2"; package labparcels.case1 version "0.1.0"; namespace "urn:law:lab:parcels:case1"; [authoring] local_imports = "explicit" ``` Re-pin against the renamed revisions. The first wire carries no addition line; each later wire names its addition. The exports of the first wire already speak the new word: ```shell law add 'labparcels.iface@0.2.0' --project /tmp/lab-work/stage-b/case1-holds --registry lab=/tmp/lab-work/stage-b/registry --from lab law add 'labparcels.registry@0.3.0' --project /tmp/lab-work/stage-b/case1-holds --registry lab=/tmp/lab-work/stage-b/registry --from lab law add 'labparcels.fees@0.4.0' --project /tmp/lab-work/stage-b/case1-holds --registry lab=/tmp/lab-work/stage-b/registry --from lab law add 'labparcels.appeals@0.2.0' --project /tmp/lab-work/stage-b/case1-holds --registry lab=/tmp/lab-work/stage-b/registry --from lab ``` ```text lab ← /tmp/lab-work/stage-b/registry (--registry) exports (7): Owner, Parcel, ParcelKind, commercial, garden, holds, residential changed: .law/transport.json changed: deps/labparcels.iface.lawir.json changed: law.lock changed: law.toml changed: package.law lab ← /tmp/lab-work/stage-b/registry (--registry) + labparcels.registry 0.3.0 exports (7): Owner, Parcel, ParcelKind, kind_of, registered, transfer_granted, transfer_request changed: deps/labparcels.registry.lawir.json changed: law.lock changed: law.toml changed: package.law lab ← /tmp/lab-work/stage-b/registry (--registry) + labparcels.fees 0.4.0 exports (3): Parcel, ParcelKind, fee_due changed: deps/labparcels.fees.lawir.json changed: law.lock changed: law.toml changed: package.law lab ← /tmp/lab-work/stage-b/registry (--registry) + labparcels.appeals 0.2.0 exports (4): Parcel, appeal_filed, appeal_timely, appeal_window changed: deps/labparcels.appeals.lawir.json changed: law.lock changed: law.toml changed: package.law ``` Restore the saved body with the new import lines and run the recomposed world. Four passing scenarios, and the pins hold: ```shell perl -pi -e 's/import labparcels\.iface version "0.1.0"/import labparcels.iface version "0.2.0"/; s/import labparcels\.registry version "0.1.0"/import labparcels.registry version "0.3.0"/; s/import labparcels\.fees version "0.2.0"/import labparcels.fees version "0.4.0"/; s/import labparcels\.appeals version "0.1.0"/import labparcels.appeals version "0.2.0"/' /tmp/lab-work/stage-b/case1-body.law cp /tmp/lab-work/stage-b/case1-body.law /tmp/lab-work/stage-b/case1-holds/package.law cat /tmp/lab-work/stage-b/case1-holds/package.law law test /tmp/lab-work/stage-b/case1-holds law engine lock /tmp/lab-work/stage-b/case1-holds --check ``` ```law language "law.core" version "0.2"; package labparcels.case1 version "0.1.0"; namespace "urn:law:lab:parcels:case1"; import labparcels.iface version "0.2.0"; import labparcels.registry version "0.3.0"; import labparcels.fees version "0.4.0"; import labparcels.appeals version "0.2.0"; law test labparcels.case1: world labparcels.case1, labparcels.appeals, labparcels.fees, labparcels.iface, labparcels.registry ok [labparcels.case1#authored] tests/01-worked-parcel.lawtest / urn:lab:parcels:case1:fee ok [labparcels.case1#authored] tests/01-worked-parcel.lawtest / urn:lab:parcels:case1:transfer ok [labparcels.case1#authored] tests/01-worked-parcel.lawtest / urn:lab:parcels:case1:appeal ok [labparcels.case1#authored] tests/01-worked-parcel.lawtest / urn:lab:parcels:case1:wrong-fee total: 4 checked, 4 passed, 0 failed, 0 not run; code 0 lock: /tmp/lab-work/stage-b/case1-holds/law.lock matches law.toml and resources ``` All three questions are established again on the recomposed world — including the residential fee of 100. The words changed; the meaning held: ```shell law ask /tmp/lab-work/stage-b/case1-holds --case ParcelTransfer --query-json /tmp/lab-work/stage-b/case1-holds/queries/fee-answered.json --format text | grep -E '^(Установлено|Не установлено)|resultHash' law ask /tmp/lab-work/stage-b/case1-holds --case ParcelTransfer --query-json /tmp/lab-work/stage-b/case1-holds/queries/transfer-answered.json --format text | grep -E '^(Установлено|Не установлено)|resultHash' law ask /tmp/lab-work/stage-b/case1-holds --case ParcelTransfer --query-json /tmp/lab-work/stage-b/case1-holds/queries/appeal-answered.json --format text | grep -E '^(Установлено|Не установлено)|resultHash' ``` ```text Установлено ли, что «fee_due» (parcel: `p1`, сумма: 100)? Установлено, что «fee_due» (parcel: `p1`, сумма: 100); обратное не установлено. *Вопрос `urn:law:lab:parcels:case1#case/ParcelTransfer/query/fee-answered` · результат `urn:result:case1#case/ParcelTransfer/query/fee-answered` · resultHash `sha256:b1d5c0e168fcea1b73d2b866c318bca3819880bf387bde8748b4f7c0f9c2c70b` · программа `sha256:fbc0a3e0672a032b1067437836c5235699afbc2ef782fef02735a390a0206c74` · вербализация law.verb.ru@0.39.0 · язык ru-KZ · подробность: полное дерево* Установлено ли, что «transfer_granted» (parcel: `p1`, from: `amy`, to: `bob`)? Установлено, что «transfer_granted» (parcel: `p1`, from: `amy`, to: `bob`); обратное не установлено. *Вопрос `urn:law:lab:parcels:case1#case/ParcelTransfer/query/transfer-answered` · результат `urn:result:case1#case/ParcelTransfer/query/transfer-answered` · resultHash `sha256:aee6b764655df1eccb79baa34a709a806540c1e1c4f520e8bc9344f591f4aac0` · программа `sha256:fbc0a3e0672a032b1067437836c5235699afbc2ef782fef02735a390a0206c74` · вербализация law.verb.ru@0.39.0 · язык ru-KZ · подробность: полное дерево* Установлено ли, что «appeal_timely» (parcel: `p1`)? Установлено, что «appeal_timely» (parcel: `p1`); обратное не установлено. *Вопрос `urn:law:lab:parcels:case1#case/ParcelTransfer/query/appeal-answered` · результат `urn:result:case1#case/ParcelTransfer/query/appeal-answered` · resultHash `sha256:72843c5f667bb1cee91445862cbcd68143f69fc51ac69f1420012cebd897b621` · программа `sha256:fbc0a3e0672a032b1067437836c5235699afbc2ef782fef02735a390a0206c74` · вербализация law.verb.ru@0.39.0 · язык ru-KZ · подробность: полное дерево* ``` ## How the fixtures were wired Each fixture started from the scaffolder. A norm package: ```shell law init /tmp/lab-work/init-pkg --name demo.shape --template package ``` ```text /tmp/lab-work/init-pkg: law.toml, source.law ``` A case package: ```shell law init /tmp/lab-work/init-case --name demo.matter --template case ``` ```law /tmp/lab-work/init-case: case package demo.matter, law.core language 0.2 created: law.toml, package.law, main.lawcase, law.lock case Main declared in main.lawcase and registered in law.toml; set the time axis by explicit input next: law add → law install → law ask ``` The rest of this section replays the wiring on scratch copies, so the fixtures stay untouched. Start from the extracted bundle root (`corpus-lab/`), and keep both roots explicit: the generator below exists only in the checkout composition, so it runs in a subshell there while every other command stays in the bundle root. Set `ARXO_CHECKOUT` to the absolute path of a full repository checkout before you begin: ```shell mkdir -p /tmp/lab-work/wire cp -r fixtures/parcels-registry /tmp/lab-work/wire/reg cp -r fixtures/parcels-iface /tmp/lab-work/wire/iface BUNDLE_ROOT="$(pwd)" : "${ARXO_CHECKOUT:?absolute path to the full checkout}" ``` Empty the generated fragment block on the copy and regrow it with the writing form; the check form confirms it, and the diff proves the regrown bytes match the shipped file: ```shell python3 -c "import re; p='/tmp/lab-work/wire/reg/sources.law'; t=open(p).read(); open(p,'w').write(re.sub(r'// BEGIN GENERATED.*?// END GENERATED PARCEL RULE FRAGMENTS', '// BEGIN GENERATED PARCEL RULE FRAGMENTS\n\n// END GENERATED PARCEL RULE FRAGMENTS', t, flags=re.S))" ( cd "$ARXO_CHECKOUT" || exit 1 ./law gen pinning /tmp/lab-work/wire/reg --write && ./law gen pinning /tmp/lab-work/wire/reg ) && diff /tmp/lab-work/wire/reg/sources.law \ "$BUNDLE_ROOT/fixtures/parcels-registry/sources.law" && echo SOURCES-IDENTICAL ``` ```text ✎ pinning.toml → sources.law [en-US] (2 articles) — block rewritten ✓ pinning.toml → sources.law [en-US] (2 articles) SOURCES-IDENTICAL ``` The pinned bytes live beside the pinning file under resources rather than sources, because the dependency commands stage that directory — and not the other — into the copy they verify. Empty the import block in the rules file and unwire the copy, then regrow the block with the per-package form: ```shell python3 -c "import re; p='/tmp/lab-work/wire/reg/package.law'; t=open(p).read(); open(p,'w').write(re.sub(r'\nuse self::\{[^}]*\};\n', '\n', t))" rm -rf /tmp/lab-work/wire/reg/deps law fix imports /tmp/lab-work/wire/reg ``` ```text /tmp/lab-work/wire/reg package.law +PARCEL_RULE_1 +PARCEL_RULE_2 incomplete analysis (entries are not removed): the package has `import`, but no context was presented: neither `deps/` nor `corpus/clir` (`--imports `) ``` The note about the missing import context is expected at that point — `deps/` was just removed — and the run exits 1, but the block is still written. Now pin the dependency through the registry built in the versions exercise. A package with one dependency wires in a single call on complete sources: ```shell python3 -c "p='/tmp/lab-work/wire/reg/law.toml'; t=open(p).read(); open(p,'w').write(t.split('[dependencies]')[0].rstrip()+'\n')" rm -f /tmp/lab-work/wire/reg/law.lock law add 'labparcels.iface@0.1.0' --project /tmp/lab-work/wire/reg --registry lab=/tmp/lab-work/registry --from lab law fix imports /tmp/lab-work/wire/reg --check law test /tmp/lab-work/wire/reg | tail -n 1 ``` ```text lab ← /tmp/lab-work/registry (--registry) exports (7): Owner, Parcel, ParcelKind, commercial, garden, owns, residential changed: .law/transport.json changed: deps/labparcels.iface.lawir.json changed: law.lock changed: law.toml /tmp/lab-work/wire/reg `use self` blocks are canonical total: 4 checked, 4 passed, 0 failed, 0 not run; code 0 ``` With the dependency pinned, the check form reports the blocks canonical and the four scenarios pass. The shared vocabulary package has no dependencies, so its lock came straight from the lock writer. The writer names the file it rewrote; the diff and the scenarios confirm the rewritten bytes: ```shell rm -f /tmp/lab-work/wire/iface/law.lock law engine lock /tmp/lab-work/wire/iface --write diff /tmp/lab-work/wire/iface/law.lock \ "$BUNDLE_ROOT/fixtures/parcels-iface/law.lock" && echo IFACE-LOCK-IDENTICAL law test /tmp/lab-work/wire/iface | tail -n 1 ``` ```text written /tmp/lab-work/wire/iface/law.lock IFACE-LOCK-IDENTICAL total: 2 checked, 2 passed, 0 failed, 0 not run; code 0 ``` Each call verifies the package against the pins it would leave behind, so a package that names two dependencies cannot wire both in one call: the first call would face references the second has not pinned yet. Grow such a package one dependency at a time — pin, write the references the pin unlocks, pin again — or wire a bare header first and restore the body after the last pin. The fees, appeals, and case fixtures were completed the second way; the tool writes the import lines itself, and the restored bodies kept the new lines. The renamed revisions in the later stages were wired the same way. The service directory the calls leave behind is local state and ships with no fixture. ## Why each silence holds | scenario | why the answer stays silent | |---|---| | a stranger's holding | no holding for that owner is asserted anywhere | | a holding without a recorded kind | the registration rule needs both halves | | a transfer asked by a non-owner | the asker must equal the recorded owner | | a kind without a holding | without a holding nothing is registered, and fees need registration | | the wrong amount for a kind | each kind carries exactly one amount | | a filing past the window end | the filing day must sit inside the window bounds | | a filing without registration | timeliness needs a registered parcel first | | the case mirror of the wrong amount | same single-amount reason, over the full world | | the old amount under the new rate | same single-amount reason, one revision later | | a stranger's holding on the renamed link | same silence as before, under the new word | Back to [the tour](/corpus/lab/).