Skip to content

Sources and legal time

A rule in Arxo is anchored to the text it formalizes, and the text is pinned by hash. The rule also knows when it is in force. This page adds both to the parking-permit package: the town’s rules as a pinned document, an anchor from the rule to article 2, and an edition of 2027 that introduces a fee waiver for electric vehicles. The same question is then asked at three legal dates.

Open this package in the playground → — edit the rules and the scenarios of this page and run them in your browser.

Four declarations describe a source at four levels: the work (which act), the edition (which text, in force from when), the publication (which bytes), and the fragment (which passage).

language "law.core" version "0.2";
package demo.parking version "0.1.0";
namespace "urn:law:demo:parking";
source PARKING_RULES {
kind municipal_act;
jurisdiction NORTHBRIDGE;
number "2026-1";
label en official "Northbridge Residential Parking Rules";
}
edition PARKING_RULES_2026 of PARKING_RULES {
language en;
officiality official;
adopted @2025-12-01;
in_force [@2026-01-01, infinity);
materialization_status PINNED_OFFICIAL_BYTES;
}

PINNED_OFFICIAL_BYTES is a promise: every fragment of this edition must carry a hash, and the bytes must be available. The publication names the file next to the package and the hash of the whole document; the fragment quotes article 2 and carries the hash of that passage. Both hashes are verified by law engine check — a changed byte in the file, or a retyped word in the quotation, fails the check.

publication PARKING_RULES_2026_TEXT of PARKING_RULES_2026 {
media_type "text/plain; charset=utf-8";
uri "urn:demo:parking:rules:2026";
retrieved_at @2026-01-05T09:00:00Z;
content_hash "sha256:9060e85e1fd30cd22b8a9f618afb8aabd15ae356b23b47f86ab1689b6aacb660";
local_path "sources/parking-rules-2026.txt";
}
fragment PARKING_RULES_2026_ART2 in PARKING_RULES_2026 {
kind article;
locator "article/2";
label en official "Article 2. Eligibility";
text en official """A residential parking permit is issued to an applicant who is a resident of Northbridge and has a vehicle registered at their address.
""";
content_hash "sha256:e309c8a75c1eab992dd0ad66ff477f9111bf99651e167ce1de6a651129a758be";
}

The 2027 edition exists as a description only — no bytes are pinned, so its status is ABSTRACT_ONLY, and the quoted text is marked as the author’s own (unofficial).

edition PARKING_RULES_2027 of PARKING_RULES {
language en;
officiality official;
adopted @2026-11-15;
in_force [@2027-01-01, infinity);
materialization_status ABSTRACT_ONLY;
}
fragment PARKING_RULES_2027_ART3A in PARKING_RULES_2027 {
kind article;
locator "article/3a";
text en unofficial """Draft: no fee is charged for a permit issued for an electric vehicle.""";
}

@source(…) in front of a rule is the anchor: it ties the rule to the fragment, and every answer derived through the rule carries the passage as its source. The effective window says when the rule takes part in a computation; it is compared with the legal_time of the case.

entity Applicant;
relation resident(a: Applicant) kind institutional;
relation vehicle_registered(a: Applicant) kind institutional;
relation electric_vehicle(a: Applicant) kind empirical;
relation permit_eligible(a: Applicant) kind institutional;
relation fee_waived(a: Applicant) kind institutional;
@source(PARKING_RULES_2026_ART2)
rule PermitEligibility strict {
effective [@2026-01-01, infinity);
for a: Applicant;
when resident(a) and vehicle_registered(a);
then permit_eligible(a);
}

The waiver rule has no effective clause of its own. It is anchored to a fragment of the 2027 edition, and that edition’s in_force decides when the rule participates.

@source(PARKING_RULES_2027_ART3A)
rule ElectricFeeWaiver strict {
for a: Applicant;
when permit_eligible(a) and electric_vehicle(a);
then fee_waived(a);
}

The facts are the same in every scenario: Ann is a resident with a registered electric vehicle. Only legal_time changes.

Before the rules were in force, the eligibility rule is not applied:

test "December 2025: the rules are not yet in force" {
given {
context { legal_time @2025-12-15; decision_time @2025-12-15T09:00:00Z; knowledge_time @2025-12-15T09:00:00Z; timezone "UTC"; }
assert resident(entity_ref("urn:demo:parking:ann")) { id "ann-resident"; origin case_input; }
assert vehicle_registered(entity_ref("urn:demo:parking:ann")) { id "ann-vehicle"; origin case_input; }
assert electric_vehicle(entity_ref("urn:demo:parking:ann")) { id "ann-electric"; origin case_input; }
}
evaluate truth(permit_eligible(entity_ref("urn:demo:parking:ann")));
expect truth_status == NEITHER;
expect not applied(PermitEligibility);
}

In 2026 she is eligible, but the waiver belongs to an edition that is not yet in force:

test "March 2026: eligible, no waiver yet" {
given {
context { legal_time @2026-03-01; decision_time @2026-03-01T09:00:00Z; knowledge_time @2026-03-01T09:00:00Z; timezone "UTC"; }
assert resident(entity_ref("urn:demo:parking:ann")) { id "ann-resident"; origin case_input; }
assert vehicle_registered(entity_ref("urn:demo:parking:ann")) { id "ann-vehicle"; origin case_input; }
assert electric_vehicle(entity_ref("urn:demo:parking:ann")) { id "ann-electric"; origin case_input; }
}
evaluate truth(permit_eligible(entity_ref("urn:demo:parking:ann")));
expect truth_status == TRUE_ONLY;
expect applied(PermitEligibility);
}
test "March 2026: the waiver is not applied" {
given {
context { legal_time @2026-03-01; decision_time @2026-03-01T09:00:00Z; knowledge_time @2026-03-01T09:00:00Z; timezone "UTC"; }
assert resident(entity_ref("urn:demo:parking:ann")) { id "ann-resident"; origin case_input; }
assert vehicle_registered(entity_ref("urn:demo:parking:ann")) { id "ann-vehicle"; origin case_input; }
assert electric_vehicle(entity_ref("urn:demo:parking:ann")) { id "ann-electric"; origin case_input; }
}
evaluate truth(fee_waived(entity_ref("urn:demo:parking:ann")));
expect truth_status == NEITHER;
expect not applied(ElectricFeeWaiver);
}

In 2027 both rules participate:

test "February 2027: the waiver applies" {
given {
context { legal_time @2027-02-01; decision_time @2027-02-01T09:00:00Z; knowledge_time @2027-02-01T09:00:00Z; timezone "UTC"; }
assert resident(entity_ref("urn:demo:parking:ann")) { id "ann-resident"; origin case_input; }
assert vehicle_registered(entity_ref("urn:demo:parking:ann")) { id "ann-vehicle"; origin case_input; }
assert electric_vehicle(entity_ref("urn:demo:parking:ann")) { id "ann-electric"; origin case_input; }
}
evaluate truth(fee_waived(entity_ref("urn:demo:parking:ann")));
expect truth_status == TRUE_ONLY;
expect applied(ElectricFeeWaiver);
}

Put the document at sources/parking-rules-2026.txt next to parking.law (its text is the one quoted above, plus articles 1 and 3; the file published with this page is parking-rules-2026.txt).

Terminal window
law engine check parking.law
law engine test tests/legal-time.lawtest --program parking.law
check OK: parking.law
test PASS: December 2025: the rules are not yet in force
test PASS: March 2026: eligible, no waiver yet
test PASS: March 2026: the waiver is not applied
test PASS: February 2027: the waiver applies

Edit the quotation in the fragment — replace “an applicant” with “any applicant” — and run the check again. The passage no longer matches its hash, and the package is refused:

parking.law:34:18: error LDC-E5201: fragment "PARKING_RULES_2026_ART2": hash официального текста (en) не совпадает с объявленным content_hash … (объявлен sha256:e309c8a7…, фактический sha256:6f2239a5…)
parking.law:32:5: error LDC-E5202: fragment "PARKING_RULES_2026_ART2": официальный текст (en) не найден в закреплённых байтах публикации "PARKING_RULES_2026_TEXT" …

Restore the text and instead change one character in sources/parking-rules-2026.txt: now the document hash fails (LDC-E5204: publication "PARKING_RULES_2026_TEXT": байты "sources/parking-rules-2026.txt" не дают объявленный content_hash …). Pinning works in both directions — the quotation cannot drift from the document, and the document cannot drift from what was formalized.

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

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