Skip to content
docs
Arxo ↗

Worked solutions

For LLMs19 sections

Complete records for the tour: 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.

Run everything below from the extracted bundle root (corpus-lab/). The tour materials, plus the silent scratch directory setup:

Terminal
ls -d fixtures/parcels-*
ls templates/*.md
mkdir -p /tmp/lab-work
Output
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):

Terminal
law version
Output
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:

Terminal
law query --list 2>&1 | head -n 1
law gen pinning 2>&1 | head -n 1
Output
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.

Shared vocabulary, two scenarios:

Terminal
law test fixtures/parcels-iface
Output
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:

Terminal
law test fixtures/parcels-registry
Output
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:

Terminal
law test fixtures/parcels-fees
Output
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:

Terminal
law test fixtures/parcels-appeals
Output
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:

Terminal
law test fixtures/parcels-case1
Output
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:

Terminal
law test fixtures/parcels-fees-0.3.0
Output
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:

Terminal
law test fixtures/parcels-iface-0.2.0
Output
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:

Terminal
law test fixtures/parcels-registry-0.3.0
Output
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:

Terminal
law test fixtures/parcels-fees-0.4.0
Output
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:

Terminal
law test fixtures/parcels-appeals-0.2.0
Output
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

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 lineMeaning
# Ответ по делу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
см. шаг NSee 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:

Terminal
law ask fixtures/parcels-case1 --case ParcelTransfer --query-json fixtures/parcels-case1/queries/fee-answered.json --format text
Output
# Ответ по делу
> **Дисклеймер.** Ответ получен исполнением формализованной модели на данных дела. Это не официальный текст акта и не юридическое заключение.
## Вопрос
Установлено ли, что «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:

Terminal
law ask fixtures/parcels-case1 --case ParcelTransfer --query-json fixtures/parcels-case1/queries/transfer-answered.json --format text
Output
# Ответ по делу
> **Дисклеймер.** Ответ получен исполнением формализованной модели на данных дела. Это не официальный текст акта и не юридическое заключение.
## Вопрос
Установлено ли, что «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:

Terminal
law ask fixtures/parcels-case1 --case ParcelTransfer --query-json fixtures/parcels-case1/queries/appeal-answered.json --format text
Output
# Ответ по делу
> **Дисклеймер.** Ответ получен исполнением формализованной модели на данных дела. Это не официальный текст акта и не юридическое заключение.
## Вопрос
Установлено ли, что «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
{"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.

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):

Output
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:

QuestionWhat 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:

Terminal
./law query producers --project docs/corpus/lab/fixtures/parcels-registry --param predicate=urn:law:lab:parcels:registry#registered --param pkg=labparcels.registry
Output
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:

Terminal
./law query readers --project docs/corpus/lab/fixtures/parcels-case1 --param predicate=urn:law:lab:parcels:iface#owns --param pkg='labparcels.*'
Output
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:

Terminal
./law query anchors-of --project docs/corpus/lab/fixtures/parcels-registry --param node=urn:law:lab:parcels:registry#RegistrationComplete --param pkg=labparcels.registry
Output
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:

Terminal
./law query type-step --project docs/corpus/lab/fixtures/parcels-registry --param type=urn:law:lab:parcels:registry#Parcel --param pkg=labparcels.registry
Output
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:

Terminal
./law query imports-of --project docs/corpus/lab/fixtures/parcels-case1 --param pkg=labparcels.case1
Output
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:

Terminal
./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))"
Output
[
{
"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:

Terminal
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']]"
Output
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.

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:

Terminal
./law gen pinning docs/corpus/lab/fixtures/parcels-registry
Output
✓ pinning.toml → sources.law [en-US] (2 articles)

The audit over the same fixture:

Terminal
./law audit docs/corpus/lab/fixtures/parcels-registry
Output
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:

Terminal
law fix imports fixtures/parcels-registry --check
Output
fixtures/parcels-registry
`use self` blocks are canonical

The manifest reading:

Terminal
law engine manifest fixtures/parcels-registry/law.toml
Output
{"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:

Terminal
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
Output
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:

Terminal
law install --offline --project fixtures/parcels-registry
Output
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.

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:

Terminal
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
Output
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:

Terminal
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
Output
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:

Terminal
law outdated --project fixtures/parcels-fees --registry lab=/tmp/lab-work/registry
law outdated --project fixtures/parcels-case1 --registry lab=/tmp/lab-work/registry
Output
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:

Terminal
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:

Output
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:

Terminal
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
Output
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:

Terminal
law outdated --project fixtures/parcels-fees --registry lab=/tmp/lab-work/registry
Output
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:

Terminal
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
Output
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:

Terminal
law update 'labparcels.registry@0.2.0' --project /tmp/lab-work/fees-upd --registry lab=/tmp/lab-work/registry
Output
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:

Terminal
law test /tmp/lab-work/fees-upd | tail -n 1
law outdated --project /tmp/lab-work/fees-upd --registry lab=/tmp/lab-work/registry
Output
total: 5 checked, 5 passed, 0 failed, 0 not run; code 0
Output
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:

Terminal
law update 'labparcels.registry@0.9.9' --project /tmp/lab-work/fees-upd --registry lab=/tmp/lab-work/registry
Output
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:

Terminal
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)
Output
✗ pinning.toml → sources.law [en-US] (2 articles)
Output
✗ 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.""";

Pack the original five states plus the fee revision into the stage directory:

Terminal
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
Output
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:

Terminal
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
Output
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:

Terminal
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
Output
*Вопрос `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:

Terminal
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'])"
Output
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:

Terminal
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
Output
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:

Terminal
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
Output
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:

Terminal
law test /tmp/lab-work/stage-a/case1
Output
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 translates the rest:

Terminal
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'
Output
Установлено ли, что «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:

Terminal
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'
Output
Установлено ли, что «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:

Terminal
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'
Output
Установлено ли, что «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:

Arxo Law
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;
}
Terminal
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
Output
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:

Terminal
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
Output
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.

Pack the original five states plus the four renamed revisions:

Terminal
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
Output
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:

Terminal
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
Output
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:

Terminal
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
Output
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:

Terminal
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
Output
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:

Arxo 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);
}
Terminal
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
Output
/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:

Terminal
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
Arxo 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:

Terminal
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
Output
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:

Terminal
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
Arxo 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:

Terminal
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'
Output
Установлено ли, что «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 · подробность: полное дерево*

Each fixture started from the scaffolder. A norm package:

Terminal
law init /tmp/lab-work/init-pkg --name demo.shape --template package
Output
/tmp/lab-work/init-pkg: law.toml, source.law

A case package:

Terminal
law init /tmp/lab-work/init-case --name demo.matter --template case
Arxo 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 <package> → 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:

Terminal
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:

Terminal
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
Output
✎ 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:

Terminal
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
Output
/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 <context.json>`)

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:

Terminal
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
Output
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:

Terminal
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
Output
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.

scenariowhy the answer stays silent
a stranger’s holdingno holding for that owner is asserted anywhere
a holding without a recorded kindthe registration rule needs both halves
a transfer asked by a non-ownerthe asker must equal the recorded owner
a kind without a holdingwithout a holding nothing is registered, and fees need registration
the wrong amount for a kindeach kind carries exactly one amount
a filing past the window endthe filing day must sit inside the window bounds
a filing without registrationtimeliness needs a registered parcel first
the case mirror of the wrong amountsame single-amount reason, over the full world
the old amount under the new ratesame single-amount reason, one revision later
a stranger’s holding on the renamed linksame silence as before, under the new word

Back to the tour.

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

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