Skip to content
docs
Arxo ↗

The lab: parcels fixtures tour

For LLMs14 sections

Five small fictional packages form a parcel registry that never existed: parcels, owners, registration, fees, appeals, and one worked case. The domain is invented on purpose, so no training sentence can be mistaken for law. Every command below runs against these fixtures, and every expected result on this page was recorded by running the tool.

Environment: the public law-v0.1.1 release on PATH, commands run from the extracted bundle root (corpus-lab/), input files from the lab archive. One route also needs a source checkout; its section says so.

The lab supports three routes. Each one stands on its own; start with the first run if this is your first visit.

RouteWhat the reader getsSections
First runfive initial packages, their tests, three questions on the case, and how to read the answersBefore you start, Run the world, Ask the case
Changing the corpuspublishing a version, changing the fee rate, migrating the shared vocabularyVersions, hands-on, Stage A, Stage B
Structure and sourcesstructural queries, pinning, and extra checks; requires a source checkout (I) for query and genRead the structure, Provenance and shape

Negative cases lists the expected no-answers of all three routes, and Templates holds the copy-paste aids the second route uses. Complete transcripts for every command are in the worked solutions.

The install routes on the Install page deliver the binary only: a package manager, a setup script, or a release archive, each carrying the same release bytes. None of them carries the tour fixtures. The fixtures, templates, and check scripts ship as one self-contained archive instead — start from an empty directory:

Terminal
mkdir -p ~/corpus-lab-run && cd ~/corpus-lab-run
curl -O https://docs.arxo.io/build/corpus-lab-bundle.tar.gz
curl -O https://docs.arxo.io/build/corpus-lab-bundle.tar.gz.sha256
shasum -a 256 -c corpus-lab-bundle.tar.gz.sha256
tar xzf corpus-lab-bundle.tar.gz
shasum -a 256 -c corpus-lab/MANIFEST.sha256
cd corpus-lab
ls -d fixtures/parcels-*
mkdir -p /tmp/lab-work

The first check confirms the download. The manifest check confirms every extracted file. Run it from the directory that holds corpus-lab/, because the manifest paths carry that prefix. Run it without a pipe, so that a failure exit is not lost. The listing names ten fixture directories: the five without a version suffix are the first run; the suffixed ones are later revisions, introduced in the exercise that uses them. Everything the tour writes lands under /tmp/lab-work; the fixtures stay unchanged. Every fixture path in the tour is relative to the bundle root (fixtures/...).

Then confirm the build:

Terminal
law version

Expected: the first line reads law 0.1.1. This means the public release the transcripts were recorded on is the one on your PATH. The full block, with the per-platform binary hash, is under Reproduction details.

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, and the fee scenario fails there. The checkout is needed only by the two sections of the third route, and each of them names its own prerequisites.

The first run uses five packages:

fixturepackageversionrole
parcels-ifacelabparcels.iface0.1.0shared vocabulary: parcels, owners, the holding link, the kind list
parcels-registrylabparcels.registry0.1.0the act: two pinned articles plus the rules that apply them
parcels-feeslabparcels.fees0.2.0first consumer: the fee each registered parcel owes
parcels-appealslabparcels.appeals0.1.0second consumer: whether an appeal arrived inside its window
parcels-case1labparcels.case10.1.0the worked case: one parcel, three questions, recorded answers

All five declare the same language line and the explicit import style. The fees package sits at 0.2.0 while its neighbours sit at 0.1.0, so the world mixes versions from the start; the versions exercise turns that into hands-on work. The other five fixture directories are later revisions of the same packages: Stage A and Stage B introduce them.

Each fixture ships its scenarios and its pinned world, so law test passes with no setup. Run the five in dependency order.

Terminal
law test fixtures/parcels-iface

Expected last line: total: 2 checked, 2 passed, 0 failed, 0 not run; code 0. The shared vocabulary holds on its own, with no dependencies.

Terminal
law test fixtures/parcels-registry

Expected last line: total: 4 checked, 4 passed, 0 failed, 0 not run; code 0. The act works over the shared vocabulary: registration and transfer, each with one case where nothing should follow.

Terminal
law test fixtures/parcels-fees
law test fixtures/parcels-appeals

Expected last lines: total: 5 checked, 5 passed, 0 failed, 0 not run; code 0 for the fees and total: 3 checked, 3 passed, 0 failed, 0 not run; code 0 for the appeals. Both consumers read the act through their pins.

Terminal
law test fixtures/parcels-case1

Expected last line: total: 4 checked, 4 passed, 0 failed, 0 not run; code 0. The whole five-package world is consistent, and the case can be asked.

Several scenarios expect silence rather than a verdict: a stranger’s holding, a missing kind, a late filing, a wrong amount. Silence there is the correct behaviour. The full transcripts, with every scenario name, are the first worked solution, and why each silence holds explains each one.

Background reading on packages and worlds lives under several packages and a world and packages and cases.

The parcels-case1 fixture pins one matter: Amy holds parcel p1, the parcel is residential, Amy asks to transfer it to Bob, and an appeal arrives on day 25 of a window running from day 10 to day 40. Three question files ship with the fixture; each asks whether one conclusion holds.

Terminal
law ask fixtures/parcels-case1 --case ParcelTransfer --query-json fixtures/parcels-case1/queries/fee-answered.json --format text

Expected, in the answer section (## Ответ) of the recorded transcript:

Output
Вычисление завершено.
Установлено, что «fee_due» (parcel: `p1`, сумма: 100); обратное не установлено.

The answer shell speaks Russian while the fixture words stay English. The first line says the evaluation completed. The second line says the fee of 100 for p1 is established and its opposite is not. The grounds below it lead from the rule FeeResidential to the registration rule, which cites article 1 of the pinned edition, and then to the two case facts it used.

Terminal
law ask fixtures/parcels-case1 --case ParcelTransfer --query-json fixtures/parcels-case1/queries/transfer-answered.json --format text

Expected, in the answer section:

Output
Вычисление завершено.
Установлено, что «transfer_granted» (parcel: `p1`, from: `amy`, to: `bob`); обратное не установлено.

The transfer from Amy to Bob is established. Its first ground cites article 2; the registration step under it cites article 1.

Terminal
law ask fixtures/parcels-case1 --case ParcelTransfer --query-json fixtures/parcels-case1/queries/appeal-answered.json --format text

Expected, in the answer section:

Output
Вычисление завершено.
Установлено, что «appeal_timely» (parcel: `p1`); обратное не установлено.

The appeal is timely: the grounds name the filing on day 25 and the window from day 10 to day 40 as case facts.

All three conclusions are established, and each proof cites the case facts and pinned articles it used. The complete records, with the footer hashes and a reading guide, are in the answers solution. One question file needs a warning: the amount travels in the compiled Integer shape, and the solutions show why that spelling is required.

How a case package is put together is covered in a package in the corpus.

Requires a source checkout (I). Prerequisites for this section only: a full repository checkout, commands run from the repository root with the ./law launcher. The public composition is smaller than the checkout one: it has no query and no gen command. To confirm that boundary on the public build:

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

LawQL questions read the formalization itself rather than any matter. The tour uses the catalogued questions; list the catalog first:

Terminal
./law query --list

Twenty-two entries answer: six named questions and sixteen checks. Five questions below run against the fixtures; each names its target package explicitly, so the snapshot stays inside the lab world.

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

One row: the strict registration rule, with its anchor on the first article.

Who reads the holding link, across the whole lab world:

Terminal
./law query readers --project docs/corpus/lab/fixtures/parcels-case1 --param predicate=urn:law:lab:parcels:iface#owns --param pkg='labparcels.*'

Two rows: both registry rules, each with the article behind it.

What the registration rule leans on, and how the parcel type resolves:

Terminal
./law query anchors-of --project docs/corpus/lab/fixtures/parcels-registry --param node=urn:law:lab:parcels:registry#RegistrationComplete --param pkg=labparcels.registry
./law query type-step --project docs/corpus/lab/fixtures/parcels-registry --param type=urn:law:lab:parcels:registry#Parcel --param pkg=labparcels.registry

One anchor row pointing at the first article; one alias step from the registry parcel type to the shared parcel type.

What the case package pulls in:

Terminal
./law query imports-of --project docs/corpus/lab/fixtures/parcels-case1 --param pkg=labparcels.case1

Four rows, one per lab dependency. The full rows are recorded with the structure solutions. The reference for the question language is the LawQL page.

The registry fixture pins two invented articles and derives both of them through rules. Four readings confirm the chain from text to machine. The first two require a source checkout (I): full repository, ./law from the repository root. The public composition has no gen, and its audit cannot see the lint catalog. First, the pinning check, which compares the fragment block in the sources file against the pinned bytes:

Terminal
./law gen pinning docs/corpus/lab/fixtures/parcels-registry

A tick and two articles answer. Second, the audit over the same fixture, which reports both articles executable, the text share they cover, and sixteen structural checks with no findings:

Terminal
./law audit docs/corpus/lab/fixtures/parcels-registry

Third, the import-block check on the registry package. The package keeps its source model and its rules in two files, and the rules file names the fragments it leans on in a block the tool maintains. Confirm the block is canonical with the per-package form of the command, which is the only form to use inside a shared tree:

Terminal
law fix imports fixtures/parcels-registry --check

Fourth, the manifest and lock readings on any fixture, plus the offline install, which confirms the pinned files already match the lock without touching the network:

Terminal
law engine manifest fixtures/parcels-registry/law.toml
law engine lock fixtures/parcels-registry --check
law install --offline --project fixtures/parcels-registry

The pinning drill is described in pin the act, edition, and publication, and the package mechanics in N. Package, context, snapshots, case, result, and test.

Everything so far was read-only. This part writes, so it works on scratch copies outside the bundle and leaves the fixtures pristine. The goal: publish the lab packages to a throwaway registry, watch the currency check pass, author a new registry revision, watch the check flag it, and move one consumer across.

Build the registry from the fixtures. Pack each package, then publish each artifact under one registry name:

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

Check currency against that registry. Both pins report up to date:

Terminal
law outdated --project fixtures/parcels-fees --registry lab=/tmp/lab-work/registry

Now author revision 0.2.0 of the registry package on a scratch copy: copy the parcels-registry fixture aside, raise its version in the manifest, in both law files, and in the four scenario files, add one small derived rule, and confirm its four scenarios still pass on the copied pins with no rewiring step. Pack and publish the revision into the same registry. Currency now flags the new revision and exits nonzero; the solutions record the exact lines.

Move a scratch copy of the fees consumer across. First preview:

Terminal
law update 'labparcels.registry@0.2.0' --project /tmp/lab-work/fees-upd --registry lab=/tmp/lab-work/registry --dry-run

Then run the same command without the preview flag, and run the consumer scenarios plus the currency check again: five passing scenarios, both pins up to date. Asking for a revision that was never published is refused; the solutions show that refusal too.

Version rules and release practice are covered in versions.

Stage A — a meaning change with the same signature

Section titled “Stage A — a meaning change with the same signature”

This stage uses one more fixture, a later revision of the fee consumer:

fixturepackageversionrole
parcels-fees-0.3.0labparcels.fees0.3.0the residential rate moves, the signature stays

The fee revision at 0.3.0 moves the residential rate from 100 to 120. Nothing else changes: the same predicate, the same argument shapes, the same commercial and garden rates. Confirm the revision passes on its own over the original world:

Terminal
law test fixtures/parcels-fees-0.3.0

Expected last line: total: 5 checked, 5 passed, 0 failed, 0 not run; code 0. The revision is consistent by itself; the stage below shows what it changes for the case. The rule that moves:

Arxo Law
rule FeeResidential strict {
for p: Parcel;
for k: ParcelKind;
when labparcels.registry::registered(p) and labparcels.registry::kind_of(p, k) and k == labparcels.iface::residential;
then fee_due(p, 120);
}

Work on scratch copies under a stage directory, with its own throwaway registry holding the original five states plus the fee revision:

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

Before moving anything, save the three old answers and replay the fee answer against its saved inputs. The replay reaches the same hash, which is the point: old inputs, old answer, no drift.

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

Now predict the move before running it. After the case crosses to the fee revision, the old residential amount goes silent, the new amount is established, and the other two verdicts stand while their hashes move with the changed program bytes:

questionbeforeafter
residential fee of 100establishedsilent
residential fee of 120silentestablished
transfer from Amy to Bobestablishedestablished, new hash
timely appealestablishedestablished, new hash

Move the scratch case across, confirm the four predictions, and run both consumers plus the case. The case run breaks exactly where predicted — its fee expectation still names the old amount — so move that expectation to the new amount and rerun until every test passes:

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
law test /tmp/lab-work/stage-a/case1
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'
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'
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'
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
law test /tmp/lab-work/stage-a/case1 | tail -n 1
law test fixtures/parcels-fees-0.3.0 | tail -n 1
law test fixtures/parcels-appeals | tail -n 1

The grep filters keep the Russian answer lines Установлено (established), Не установлено (not established), and Вычисление (evaluation), plus the resultHash footer; the answer glossary translates every recurring phrase.

The solutions record every line: the saved footers, the replay, the preview and the move, the predicted break, the four verdicts after the move, and the passing runs. The change template for a meaning shift is the shared dependency change aid.

Stage B — a shared-vocabulary interface change

Section titled “Stage B — a shared-vocabulary interface change”

This stage uses four more fixtures, the renamed line:

fixturepackageversionrole
parcels-iface-0.2.0labparcels.iface0.2.0the shared vocabulary with the holding link renamed
parcels-registry-0.3.0labparcels.registry0.3.0the act migrated to the renamed link
parcels-fees-0.4.0labparcels.fees0.4.0the fee consumer on the renamed line, original rates
parcels-appeals-0.2.0labparcels.appeals0.2.0the appeal consumer on the renamed line

The renamed line renames the holding link of the shared vocabulary from owns to holds, keeping its shape: same owner and parcel arguments, same key. The registry, fee, and appeal revisions follow the rename; rates and windows stay at their original values. Stage A and Stage B are alternative futures that branch from the original states, not a single timeline, so each can be run on its own. Confirm the four revisions pass:

Terminal
law test fixtures/parcels-iface-0.2.0
law test fixtures/parcels-registry-0.3.0
law test fixtures/parcels-fees-0.4.0
law test fixtures/parcels-appeals-0.2.0

Expect 2, 4, 5, and 3 passing scenarios, the same totals as the original states: the rename keeps every scenario. The full transcripts are with the scenario solutions. The renamed declaration:

Arxo Law
pub relation holds(owner: Owner, parcel: Parcel) kind institutional {
key(parcel);
label en unofficial "owner holds the parcel";
}

Build a second stage directory whose registry holds 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
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

First the break. Moving the unmigrated act under the renamed vocabulary is refused before anything is written: the refusal names the missing word at both rules that read it and lists the new word among the exports. A second refusal follows on the fee consumer — moving one of two coupled pins alone is a version conflict — which is why the migration below rewires pins together instead of moving them one by one:

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

Then the migration. Rename the holding link in the scratch case file and its scenarios, strip the four pins to a bare header, re-pin against the renamed revisions, and restore the body with the new import lines:

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
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
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
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
law test /tmp/lab-work/stage-b/case1-holds

Every test of the recomposed world passes, and all three case questions are established again — including the residential fee of 100, which is the point of the stage: the words changed, the meaning held. The failing moves, the four dependency wires, and the three answers are recorded with the solutions. The interface side of the change template is the shared dependency change aid alongside the public vocabulary contract promises the rename had to renegotiate.

The lab ships its no-answers alongside its answers. Each item below is exercised by the fixtures and explained in the solutions:

caseexpected behaviour
a stranger’s holdingthe vocabulary stays silent
a holding without a recorded kindregistration stays silent
a transfer asked by a non-ownerthe grant stays silent
a kind without a holdingno fee is due
the wrong amount for a kindthe fee is not established
a filing past the window endtimeliness is not established
a filing without registrationtimeliness is not established
a currency check with a newer revision publishedthe pin is flagged, nonzero exit
an update to a revision that was never publishedthe command is refused
a fragment line edited by handthe pinning check fails, and the diff names the line
the old amount after the rate changethe old fee stays unestablished; updating the expectation fixes the test, not the model
a consumer moved under renamed words without migrationthe update is refused and names the missing word
moving one of two coupled pinsrefused as a version conflict; re-pin together

The lab ships six copy-paste templates that the tour uses at each decision point. They are documentation aids, not engine input files:

Each template also ships one filled example on lab material, with pasted engine outputs recorded by running the tool:

Toolchain, hashes, and full transcripts

Transcripts on this page and in the solutions quote standard output. Compare verdicts and proof shape when you repeat the tour. The long hashes in answer footers match whenever the inputs match.

Pinned tool: the public law-v0.1.1 release, observed through law version on macOS arm64:

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

The first line is the tool version; the last line hashes the bytes behind it, so record the whole block with your run. Linux x64 reports sha256:be8b4fbb… instead; both hashes are pinned in the bundle’s PINNED.md, which also records the source revision of the archive.

The checksum file pins the archive:

Output
d274971f1618db195ea795803e9fd968c4d366903acd807ff9f2a573d0e33d0b corpus-lab-bundle.tar.gz

Full transcripts for every command of the tour, including the fixture listing and the version check, are in the worked solutions.

Worked solutions with complete transcripts: solutions.

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

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