<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: arxo</title>
    <description>The latest articles on DEV Community by arxo (@arxo).</description>
    <link>https://dev.to/arxo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3755433%2Fabc4ff8f-88f5-4b02-8570-6efd051d433e.png</url>
      <title>DEV Community: arxo</title>
      <link>https://dev.to/arxo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/arxo"/>
    <language>en</language>
    <item>
      <title>One Accident, Several Laws, One Answer</title>
      <dc:creator>arxo</dc:creator>
      <pubDate>Wed, 07 Oct 2026 19:14:36 +0000</pubDate>
      <link>https://dev.to/arxo/one-accident-several-laws-one-answer-5h95</link>
      <guid>https://dev.to/arxo/one-accident-several-laws-one-answer-5h95</guid>
      <description>&lt;p&gt;&lt;em&gt;An insurer pays 730,000 tenge. The payment is twelve days late. Following the rules from the insurance statute to the Civil Code produces another 4,020 tenge—and a record of how that amount was reached.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The money has arrived. Has the insurer finished paying?&lt;/p&gt;

&lt;p&gt;In this fictional motor-insurance case, the insurer receives the required documents on 22 July 2026 and pays 730,000 tenge on 24 August. Arxo computes the payment deadline as 12 August. Payment was late; under the stated calculation inputs, the late-payment penalty is 4,020 tenge.&lt;/p&gt;

&lt;p&gt;Each part of that answer comes from somewhere different. The insurance statute supplies the payment period and the obligation to pay a penalty. The Civil Code supplies the rule for that penalty. A National Bank rate and an official calendar supply dated values. The case supplies the payment events and an explicit assumption needed for the arithmetic.&lt;/p&gt;

&lt;p&gt;A single bank transfer has led us across several sources. The useful result is an answer whose steps can be inspected together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with events
&lt;/h2&gt;

&lt;p&gt;The example belongs to a collection of five fictional cases about Kazakhstan’s compulsory motor third-party liability insurance, known as OGPO VTS. The main case is deliberately small:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Required documents received&lt;/td&gt;
&lt;td&gt;22 July 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Insurance payment amount&lt;/td&gt;
&lt;td&gt;730,000 KZT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Actual payment date&lt;/td&gt;
&lt;td&gt;24 August 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Annual-to-daily rate divisor&lt;/td&gt;
&lt;td&gt;365, explicitly supplied&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Calendar&lt;/td&gt;
&lt;td&gt;The recorded official 2026 calendar&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The 730,000-tenge insurance payment is an input in this example. The calculation begins after that amount has been established. It does not reconstruct repair costs from photographs or decide the disputed facts of the accident.&lt;/p&gt;

&lt;p&gt;There is no input labelled “the insurer paid late.” That is one of the questions the rules must answer.&lt;/p&gt;

&lt;p&gt;This distinction matters when building a legal application. If a person supplies the conclusion and the software merely repeats it, the central reasoning remains outside the computation. Here, the case supplies two events: receipt of documents and payment. The model must connect them through the applicable deadline.&lt;/p&gt;

&lt;h2&gt;
  
  
  A deadline has dependencies
&lt;/h2&gt;

&lt;p&gt;Article 26(1) of the &lt;a href="https://adilet.zan.kz/rus/docs/Z030000446_" rel="noopener noreferrer"&gt;motor-insurance statute&lt;/a&gt; provides the general period used in this case: fifteen working days from receipt of the documents specified in Article 25.&lt;/p&gt;

&lt;p&gt;For documents received on Wednesday, 22 July, the recorded calendar and counting policy place the deadline on Wednesday, 12 August. The payment on 24 August comes after it. The late-payment period runs from 13 through 24 August, twelve calendar days.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgigh0om787wl1qlekkb5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgigh0om787wl1qlekkb5.png" alt="Documents received on 22 July; fifteen working days lead to a deadline of 12 August; payment on 24 August is twelve calendar days late." width="799" height="311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The two intervals use different clocks. Working days establish when payment falls due. Calendar days measure this period of delay. A calculation that treats both intervals as the same kind of duration can get the amount wrong even when its multiplication is correct.&lt;/p&gt;

&lt;p&gt;The calendar is therefore part of the case’s supporting data. Someone checking the deadline needs the calendar used for the calculation, alongside the date and the rule.&lt;/p&gt;

&lt;h2&gt;
  
  
  The insurance law sends us to the Civil Code
&lt;/h2&gt;

&lt;p&gt;Article 26(4) imposes a penalty for late payment and refers to Article 353 of the &lt;a href="https://adilet.zan.kz/rus/docs/K940001000_" rel="noopener noreferrer"&gt;Civil Code&lt;/a&gt; for its procedure and amount. The payment-day calculation used here takes the National Bank base rate applicable on the day the obligation is performed.&lt;/p&gt;

&lt;p&gt;In the recorded case, that annual rate is 16.75%. With the explicitly supplied divisor of 365, the arithmetic is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;730,000 KZT × 12 days × 0.1675 ÷ 365 = 4,020 KZT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The amount is exact for these inputs. The case also establishes that the obligation to pay the late-payment penalty is active.&lt;/p&gt;

&lt;p&gt;The saved analysis below compares this case with payment on the deadline itself. Both have the same deadline, 12 August; payment on 24 August establishes lateness. Open the analysis to inspect the 4,020-tenge result and the penalty obligation. The interface is available in English; the case questions are in Russian.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://lens.arxo.io/a/b_832ea4dca63da6e90fb61b9c16b61decf8a97a635f41905748061a901fa43646?lang=en" rel="noopener noreferrer"&gt;Payment on the deadline and payment twelve days later&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The implementation preserves the division of responsibility between sources. The insurance rule creates the obligation; the Civil Code provides the referenced basis; dated rate data supplies a value; an accrual calculation applies it. The connection between those parts does not introduce another legal rule of its own.&lt;/p&gt;

&lt;p&gt;That is what makes the cross-reference useful to software. A reader can follow it. An executable model can carry a result across it while retaining its origin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Remove one assumption
&lt;/h2&gt;

&lt;p&gt;The divisor of 365 deserves its own line in the input table. Article 353’s payment-day rate provision does not specify the annual-to-daily conversion convention. This model requires that convention to be supplied explicitly.&lt;/p&gt;

&lt;p&gt;Remove the divisor from the same case. The payment is still late: the dates and calendar are unchanged. But the model no longer derives a penalty amount.&lt;/p&gt;

&lt;p&gt;That outcome keeps two questions separate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Was payment late? Established.&lt;/li&gt;
&lt;li&gt;What penalty amount follows from these inputs? No amount derived.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A zero in the second field would erase that distinction. So would silently inserting a familiar financial convention. The saved explanation identifies the amount rule as unestablished; it does not itself trace the missing divisor through every intermediate calculation. The paired cases show exactly which input was removed.&lt;/p&gt;

&lt;p&gt;Now make a different change: supply both 24 and 26 August as the single payment date for the same claim. Those assertions conflict with the field’s uniqueness requirement. The evaluation is marked &lt;code&gt;NON_EXECUTABLE&lt;/code&gt;. Any amount retained in its diagnostic output must be read with that status; it is not an accepted answer to the conflicting case.&lt;/p&gt;

&lt;h2&gt;
  
  
  Move the case across a holiday
&lt;/h2&gt;

&lt;p&gt;Another case in the collection moves receipt of documents to 19 October 2026 and payment to 10 November. In the recorded calendar, Republic Day falls on Sunday, 25 October, with the day off transferred to Monday, 26 October.&lt;/p&gt;

&lt;p&gt;The deadline is 10 November. The alternative date, 9 November, is not established; payment on 10 November does not establish lateness. The saved analysis also contains the missing-divisor and conflicting-date variants.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://lens.arxo.io/a/b_c591f670223f98bf6eade6e1ccf0e9986367912d22bf07f3f199e4ab419dec3a?lang=en" rel="noopener noreferrer"&gt;A transferred holiday, a missing divisor, and conflicting payment dates&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These are small changes to one case, but they exercise different parts of the reasoning: date calculation, sufficiency of inputs, and consistency of assertions. A single “valid” checkbox would lose information the reader needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rest of the accident has its own sources
&lt;/h2&gt;

&lt;p&gt;The deadline-and-penalty example sits within a wider motor-insurance model. Following a case from policy purchase to a dispute brings further sources into view:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Where the model looks&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;What premium applies?&lt;/td&gt;
&lt;td&gt;The insurance statute, bonus-malus rules and annual adjustment coefficients&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;How is vehicle damage assessed?&lt;/td&gt;
&lt;td&gt;The vehicle-damage assessment rules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What payment limits apply?&lt;/td&gt;
&lt;td&gt;The insurance statute and the relevant budget index&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Was payment late, and what penalty follows?&lt;/td&gt;
&lt;td&gt;The insurance statute, calendar, Civil Code and dated rate data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Can the claimant use a guarantee mechanism?&lt;/td&gt;
&lt;td&gt;The Insurance Payments Guarantee Fund legislation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Can the dispute go to the insurance ombudsman?&lt;/td&gt;
&lt;td&gt;The insurance legislation governing that procedure&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These are branches with their own conditions. A dispute does not, by itself, establish eligibility for every procedure. A change in the insurer’s status calls for a fresh check of the guarantee conditions. The five cases shown here exercise the payment deadline and penalty branch.&lt;/p&gt;

&lt;p&gt;A software package can connect provisions from several acts, while one act can contribute to several stages. Regulations, annual tables and calendars matter alongside statutes. Each rule and value retains its source as the case moves between them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What one answer contains
&lt;/h2&gt;

&lt;p&gt;For the main case, a useful answer keeps four results together: the deadline is 12 August; payment on 24 August was late; the stated inputs yield a 4,020-tenge penalty; the penalty obligation is active. It also preserves the facts, rules and assumptions behind those results.&lt;/p&gt;

&lt;p&gt;The displayed analyses are saved evaluations. In a local check on 23 September 2026, all sixteen case-and-question evaluations in the captured collection matched their saved command-line evaluation documents byte for byte when run through the local WebAssembly engine. That checks reproduction on those fixed inputs; the legal interpretation and the evidence for the case remain separately reviewable.&lt;/p&gt;

&lt;p&gt;Arxo executes the canon. Models formalize; Arxo executes and proves. In this example, the practical payoff is that a reviewer can follow the path from two payment events through a deadline and a statutory cross-reference to an additional obligation.&lt;/p&gt;

&lt;p&gt;The bank transfer answers whether money arrived. The connected rules answer what that payment leaves owing.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://blog.arxo.io/one-accident-several-laws/" rel="noopener noreferrer"&gt;Arxo blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>dsl</category>
      <category>architecture</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Law as Function, Law as Data: What Catala and Arxo Compute When They Read the Same Regulation</title>
      <dc:creator>arxo</dc:creator>
      <pubDate>Tue, 06 Oct 2026 18:32:33 +0000</pubDate>
      <link>https://dev.to/arxo/law-as-function-law-as-data-what-catala-and-arxo-compute-when-they-read-the-same-regulation-1ae7</link>
      <guid>https://dev.to/arxo/law-as-function-law-as-data-what-catala-and-arxo-compute-when-they-read-the-same-regulation-1ae7</guid>
      <description>&lt;p&gt;Two independent formalizations of the same regulation, written in two different languages, agreed on every one of 65 reference cases and 240 randomly generated ones. That result is the starting point of this article, not its conclusion. Where two systems built on different foundations agree, the interesting question is what each of them computes beyond the point where the agreement ends.&lt;/p&gt;

&lt;p&gt;Catala, developed at Inria, applies programming-language theory to computational law. Its default-calculus-to-lambda-calculus compilation step is mechanized in the F* proof assistant, and its compiler targets OCaml, Python, C and Java. Legal fidelity still depends on review of the formalization alongside the source text.&lt;/p&gt;

&lt;p&gt;Arxo Law is built on a different premise. In Catala, a statute becomes a function: inputs go in, a value comes out, and the verified compilation step preserves the formal specification. In Arxo, a statute becomes data: a package of norms with byte-pinned sources, deontic positions, priorities, interpretations and editions, which an engine executes to produce a proof graph rather than a value. Both premises are principled. They answer different questions, and this article uses one shared regulation to show where each question begins.&lt;/p&gt;

&lt;h2&gt;
  
  
  The parity experiment
&lt;/h2&gt;

&lt;p&gt;The material is a Kazakh regulation: the Rules for Determining the Amount of Damage Caused to a Vehicle (Resolution No. 14 of the Board of the National Bank of the Republic of Kazakhstan, 28 January 2016). It is a compact by-law with the shape that formal methods handle best: thresholds, percentages, deadlines counted in working days, and a small set of conditions on inspections and documents.&lt;/p&gt;

&lt;p&gt;The computational part of the Rules was implemented twice, independently, from the official text:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;in Catala 1.2.0, as six scopes covering total loss, part cost, choice of appraisers, admissibility of inspection, deadlines, and the final amount;&lt;/li&gt;
&lt;li&gt;in Arxo Law, as a package whose 67 rules cover the same points plus duties, provenance and edition metadata outside the computational comparison.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Expected outcomes for 65 reference cases were established by hand from the text and the 2026 official calendar, with a written justification for each. The same 65 cases were then run through Catala and through both Arxo evaluators (the Rust engine and the Python reference implementation), and a property-based run generated 240 further random cases across two seeds, checked against a Python oracle written directly from the text.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check (9 September 2026)&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;65 reference cases, Catala against expectations&lt;/td&gt;
&lt;td&gt;65 of 65&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;65 reference cases, both Arxo evaluators&lt;/td&gt;
&lt;td&gt;all pass, results byte-identical between evaluators&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;240 random cases, oracle vs Catala&lt;/td&gt;
&lt;td&gt;240 of 240&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;240 random cases, oracle vs Arxo engine&lt;/td&gt;
&lt;td&gt;240 of 240&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20 targeted mutations of the Arxo model&lt;/td&gt;
&lt;td&gt;20 of 20 killed by the test suite&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq73051l29ijtqhg7mjgl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq73051l29ijtqhg7mjgl.png" alt="The parity experiment: one pinned regulation, formalized independently in Catala 1.2.0 as six scopes and in Arxo Law as 67 rules; 65 reference cases and 240 random cases run through both; Catala 65 of 65 and 240 of 240, Arxo 65 of 65 and 240 of 240 with two evaluators byte-identical; 20 of 20 mutations caught." width="799" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The single known semantic difference between the two languages was isolated on purpose. Catala stores money to the cent and rounds a money-times-decimal product; Arxo keeps money exact and rounds only where the text says so. The comparison was therefore fixed at whole tenge, which is also what the regulation itself requires of the final amount.&lt;/p&gt;

&lt;p&gt;A second, smaller data point comes from France. Arxo's formalization of the rental-sector housing benefit (APL) was checked against the ten test cases published in Catala's own examples repository. All ten matched to the cent, and the intermediate quantities were verified in separate scenarios (13 September 2026).&lt;/p&gt;

&lt;p&gt;The conclusion of both experiments is the same. For the tested cases, both formalizations reproduce the expected computational outcomes. This does not establish equivalence for every possible input. Everything that follows is about what lies beyond the algorithm. The vehicle-damage experiment is public: both models, the 65 reference cases, the runners and the recorded results are at &lt;a href="https://github.com/arxohq/arxo-catala-parity" rel="noopener noreferrer"&gt;github.com/arxohq/arxo-catala-parity&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Axis 1: a value versus a certificate
&lt;/h2&gt;

&lt;p&gt;The clearest architectural difference is what a single call returns.&lt;/p&gt;

&lt;p&gt;A Catala scope returns a value: a number, a boolean, an optional. This is a natural product for microsimulation, where a rules engine runs over millions of households. The Catala interpreter computed one total-loss case in about 16 microseconds in our measurement, and the compiled backends, which we did not benchmark, are designed to be faster still.&lt;/p&gt;

&lt;p&gt;An Arxo call returns an evaluation document: a manifest of inputs, the results, a proof graph with every rule application and every fact it rested on, the deontic positions in force, any registered conflicts, the issues raised, and content hashes that make the whole document reproducible. On a trivial vector this document is about three kilobytes, and those bytes are what the two Arxo evaluators compare against each other. One such call cost about 0.4 milliseconds in the Rust engine and about 2.5 milliseconds in the Python reference implementation, on the same machine and the same regulation.&lt;/p&gt;

&lt;p&gt;The measurements compare different outputs and different execution paths; they are not a controlled benchmark of the languages. Arxo spends its time on fact storage, a fixed-point computation over the rules, canonical serialization and hashing, because the product is a certificate of how the answer was reached. In this profile of the Rust engine, string comparison, map lookups and allocation account for most of the cost, and the solver itself for under one percent.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu4kkbv6oltj1mv9c1fxs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu4kkbv6oltj1mv9c1fxs.png" alt="What a call returns: in Catala, inputs go through a scope and come out as a value, about 16 microseconds per call in the interpreter; in Arxo, inputs go through the engine and come out as an evaluation document with manifest, results, proof graph, positions, conflicts, issues and content hashes, about 0.4 milliseconds per call in the Rust engine." width="800" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Measurement conditions: Apple Silicon, macOS 24.6, warm runs, 9 September 2026. Catala: the &lt;code&gt;Gibel&lt;/code&gt; scope called 10,000 times inside one process, the cost of a single-call run subtracted. Arxo: the engine's test runner over the parity scenarios, the cost of a one-test run subtracted. Process start and model loading were about 40 ms for Catala and about 10 ms for the Rust engine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Axis 2: default calculus versus four-valued support
&lt;/h2&gt;

&lt;p&gt;Catala's core is the prioritized default calculus. Each variable is defined once by a base rule and a tree of exceptions with a static priority order. If exactly one exception applies, it wins; if none applies, the base rule holds; if two exceptions of equal priority apply, the program raises a conflict error and produces no value. The world is closed: a variable has exactly one value or the computation fails.&lt;/p&gt;

&lt;p&gt;Arxo's core is a four-valued support relation with defeasible rules that preserve ambiguity. A query can be established (&lt;code&gt;TRUE_ONLY&lt;/code&gt;), refuted (&lt;code&gt;FALSE_ONLY&lt;/code&gt;), supported on both sides (&lt;code&gt;BOTH&lt;/code&gt;), or unsupported (&lt;code&gt;NEITHER&lt;/code&gt;). Silence is not negation: a fact that was never asserted does not make the opposite true.&lt;/p&gt;

&lt;p&gt;For a lawyer these two models answer differently in two common situations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A fact is missing.&lt;/strong&gt; In the Catala model we wrote, a missing input is either an omitted optional that flows through as absence, or a boolean that defaults to false. In Arxo, the query is &lt;code&gt;NEITHER&lt;/code&gt;, and the evaluation document says which premise was not established. Missing evidence and established negation are distinct statuses, and the mutation suite includes a test that breaks if they are ever conflated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two norms compete.&lt;/strong&gt; In Catala, a conflict is an error at run time, which is the correct behaviour for a system that must always produce a payment amount. In Arxo, the conflict is preserved in the answer as &lt;code&gt;BOTH&lt;/code&gt;, with both derivations in the proof graph. That is how a formalization records a genuine defect in the text or a gap in the conflict-of-laws rules instead of silently picking a side. The Lean mechanization of the semantics proves this as a theorem: when two defeasible derivations rest on incomparable grounds, both survive.&lt;/p&gt;

&lt;p&gt;Neither choice is a limitation of the other. Catala's closed world is what makes a mass-payment engine trustworthy. Arxo's open world is what makes a single disputed case explainable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5cxnyedtxq8znxy6e2ls.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5cxnyedtxq8znxy6e2ls.png" alt="Conflicts and silence: Catala's default tree gives a value when one exception applies, the base rule or nothing when none applies, and a conflict error when two apply, with an omitted input read as absent or false by field; Arxo's four statuses are established, refuted, both sides supported, and nothing concludes it, with competing norms preserved as BOTH and silence distinct from negation." width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Axis 3: what lies outside our computational model
&lt;/h2&gt;

&lt;p&gt;The vehicle-damage Rules contain more than a computation. They impose ten duties and one liberty on insurers, appraisers and victims: to inspect within a deadline, to deliver a report, to allow a second inspection, to choose an appraiser. They also delegate one quantity, depreciation, to an external methodology that the Rules do not contain, and they count deadlines in working days against the official state calendar.&lt;/p&gt;

&lt;p&gt;These parts of the regulation did not enter the Catala comparison, because we scoped that model to computational outcomes. They are first-class in Arxo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deontic positions.&lt;/strong&gt; Duty, liberty, power and immunity are declarations with a lifecycle: a duty arises, is performed, is breached or lapses inside a window. As of 9 September 2026, &lt;code&gt;power&lt;/code&gt; appeared in 189 corpus files and &lt;code&gt;immunity&lt;/code&gt; in 54; &lt;code&gt;priority&lt;/code&gt;, the declared resolution of conflicts by rank and specialty, in 321; &lt;code&gt;interpretation&lt;/code&gt;, competing readings of one text, in 127; &lt;code&gt;presumption&lt;/code&gt; in 127 and &lt;code&gt;fiction&lt;/code&gt; in 16.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The calendar as pinned data.&lt;/strong&gt; Working days are computed against a byte-pinned snapshot of the official 2026 calendar with its holiday transfers, carried into the evaluation document by hash. A case dated outside the snapshot's coverage is reported as out of calendar range rather than guessed. In the Catala program we wrote, working days were derived by folding over a list of dates supplied as input, which is entirely adequate for a fixed year and is not the same thing as a verifiable reference to the state calendar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Editions in time.&lt;/strong&gt; A query is evaluated on the date of the event against the edition of each norm in force on that date. The regulation's own amendment history is part of the package, and an answer states which edition it applied.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quantities with units.&lt;/strong&gt; A mileage in the wrong unit is a type error, not a silent conversion. In our Catala model the unit lives in the field name.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Catala's authors chose a function model deliberately, and the choice has paid off in exactly the domain it was made for. Tax and benefit calculation needs a value; it rarely needs to know which party is currently in breach of which duty. Private-law disputes, regulatory compliance and procedural law need the second thing at least as often as the first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Axis 4: two kinds of trust
&lt;/h2&gt;

&lt;p&gt;Both systems make a verification claim. The claims are about different links in the chain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Catala trusts the compiler.&lt;/strong&gt; The law text and its formalization live in one literate file, and the crucial translation from the default calculus to a lambda calculus with exceptions is mechanized in F*, with type preservation and a simulation result. This proof covers the specified core translation; it is not an end-to-end proof of every compiler backend or of the legal interpretation. What the annotation says about the law is a matter for legal review of the literate file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Arxo trusts the text and checks the proof.&lt;/strong&gt; Provenance is part of the language: every source, edition and publication carries a content hash, and the compiler rejects any quoted fragment that is not an exact substring of the pinned official publication. The evaluation document then carries a proof graph, and an independent checker written in Lean 4 (21 modules, 91 theorems and lemmas, no &lt;code&gt;sorry&lt;/code&gt;, toolchain 4.33.0, counted 19 September 2026) verifies that certificate against the least model of the monotone fragment of the semantics. The checker does not compare the two Arxo evaluators with each other; it checks each one's output against the specification. Its first run over the corpus found a dangling-reference defect that both evaluators shared and that byte-for-byte comparison could never have surfaced.&lt;/p&gt;

&lt;p&gt;Compiler correctness and certificate checking are complementary. One verifies a translation step from the formal specification; the other checks a certificate against the covered semantics. Neither proves that a formalization captures every legal meaning of the source. A mature discipline of computational law will want both.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff1p2q5gllnttgb8b9wg7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff1p2q5gllnttgb8b9wg7.png" alt="Two kinds of trust: Catala's chain runs from a literate file through a compiler whose default-calculus-to-lambda-calculus step is proven in F-star to OCaml, Python, C and Java code; Arxo's chain runs from an official publication pinned by hash through a package whose quoted fragments must be substrings, to an evaluation document with a proof graph that a Lean 4 checker verifies against the least model." width="800" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Discussion: a taxonomy, not a ranking
&lt;/h2&gt;

&lt;p&gt;The parity experiment suggests a simple way to place the two systems.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Catala&lt;/th&gt;
&lt;th&gt;Arxo Law&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;What is a norm?&lt;/td&gt;
&lt;td&gt;A function from inputs to a value&lt;/td&gt;
&lt;td&gt;A datum: text, provenance, rules, positions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What does a call return?&lt;/td&gt;
&lt;td&gt;A value&lt;/td&gt;
&lt;td&gt;An evaluation document with proof and hashes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;How are conflicts handled?&lt;/td&gt;
&lt;td&gt;Error at run time&lt;/td&gt;
&lt;td&gt;Preserved as &lt;code&gt;BOTH&lt;/code&gt; in the answer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What does silence mean in these models?&lt;/td&gt;
&lt;td&gt;Absence or false, by field&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;NEITHER&lt;/code&gt;, distinct from negation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Where is trust anchored?&lt;/td&gt;
&lt;td&gt;Verified core compilation step (F*)&lt;/td&gt;
&lt;td&gt;Pinned sources and certificate checking for the monotone fragment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best fit&lt;/td&gt;
&lt;td&gt;Mass calculation of tax and benefits&lt;/td&gt;
&lt;td&gt;Individual cases, compliance, disputes, procedure&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The two paradigms also meet in the middle. Arxo's code-generation backends print the purely computational slice of a package into a standalone TypeScript, Python or Go module that runs without the rules engine, returning answer and status without the proof (40 of 43 executed conformance vectors matched on 14 September 2026, with no divergence across the three targets; the remaining vectors were refused by the plan with a named reason). That slice is, in effect, the part of a package that Catala would also express, and it is a natural interchange point between the two worlds: computable cores could travel from one language to the other, while deontics, editions and proof stay where they are modelled.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The tested computational slice agrees: 65 reference cases and 240 random cases produced the expected outcomes in both formalizations. The 20 mutation checks apply to the Arxo model only.&lt;/p&gt;

&lt;p&gt;The practical design choice is what a caller needs beyond that result: a value, or an evaluation document that also records provenance, editions, duties and competing derivations. The experiment makes that choice concrete without establishing that either language is universally better.&lt;/p&gt;

&lt;p&gt;To inspect or reproduce the comparison, start with the &lt;a href="https://github.com/arxohq/arxo-catala-parity" rel="noopener noreferrer"&gt;public parity repository&lt;/a&gt;: it contains both models, the reference cases, runners and recorded results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Merigoux, Chataing and Protzenko, &lt;a href="https://arxiv.org/abs/2103.03198" rel="noopener noreferrer"&gt;Catala: A Programming Language for the Law&lt;/a&gt;, ICFP 2021.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/CatalaLang/catala" rel="noopener noreferrer"&gt;Catala source and releases&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/arxohq/arxo-catala-parity" rel="noopener noreferrer"&gt;Arxo–Catala parity experiment&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://blog.arxo.io/what-is-rules-as-code/" rel="noopener noreferrer"&gt;What Is Rules as Code?&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://blog.arxo.io/law-as-function-law-as-data/" rel="noopener noreferrer"&gt;Arxo blog&lt;/a&gt;. Measurements and implementation counts above are dated snapshots, not claims about later releases.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>dsl</category>
      <category>architecture</category>
      <category>opensource</category>
    </item>
    <item>
      <title>What Is Rules as Code, With a Runnable Example</title>
      <dc:creator>arxo</dc:creator>
      <pubDate>Mon, 05 Oct 2026 19:20:02 +0000</pubDate>
      <link>https://dev.to/arxo/what-is-rules-as-code-with-a-runnable-example-286f</link>
      <guid>https://dev.to/arxo/what-is-rules-as-code-with-a-runnable-example-286f</guid>
      <description>&lt;h3&gt;
  
  
  Rules as Code publishes a rule in a form a machine can execute, next to the text a person reads. Here is the definition, where the idea comes from, and a limitation period you can compute yourself.
&lt;/h3&gt;

&lt;p&gt;Rules as Code is the practice of writing a rule — a statute, a regulation, an internal policy — in a form a computer can execute, alongside the natural-language text, so that both are drafted, tested and kept in step together. The same idea travels under other names: Law as Code, Legislation as Code, machine-consumable legislation, computational law. The goal is not to automate judgment. It is to make the logic of a rule explicit, so it can be tested before it applies to anyone and reproduced after it has.&lt;/p&gt;

&lt;p&gt;A runnable rule looks like this: facts go in, a question is asked, and the answer comes back with the article it rests on. Below is one such rule, a limitation period from an international instrument, with the facts, the questions and the answers, and links to run it with your own dates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the term comes from
&lt;/h2&gt;

&lt;p&gt;In 2018 New Zealand's Service Innovation Lab ran a three-week discovery with Inland Revenue, the Ministry of Business, Innovation and Employment and the Parliamentary Counsel Office, testing the approach on two existing pieces of legislation. Its report, &lt;a href="https://www.digital.govt.nz/dmsdocument/95-better-rules-for-government-discovery-report" rel="noopener noreferrer"&gt;Better Rules for Government&lt;/a&gt;, gave the movement its name.&lt;/p&gt;

&lt;p&gt;In October 2020 the OECD's Observatory of Public Sector Innovation published &lt;a href="https://oecd-opsi.org/publications/cracking-the-code/" rel="noopener noreferrer"&gt;Cracking the Code: Rulemaking for humans and machines&lt;/a&gt;, which proposed that some government rules exist in a machine-consumable version alongside the natural-language one, and set out what that asks of drafters, lawyers and engineers.&lt;/p&gt;

&lt;p&gt;Several tools carry the idea. &lt;a href="https://openfisca.org/en/about/" rel="noopener noreferrer"&gt;OpenFisca&lt;/a&gt;, developed in France since 2011 and released as free software, models tax and benefit rules and is used to simulate the effect of new law on households and the budget. &lt;a href="https://arxiv.org/abs/2103.03198" rel="noopener noreferrer"&gt;Catala&lt;/a&gt;, from Inria and presented at ICFP 2021, is a programming language whose code follows the structure of the statute it implements; while encoding French family benefits its authors found a bug in the official implementation. &lt;a href="https://github.com/Lexpedite/blawx" rel="noopener noreferrer"&gt;Blawx&lt;/a&gt;, by Jason Morris, is a web-based tool for encoding and testing rules with answer set programming. In Germany, the federal agency SPRIND runs &lt;a href="https://www.sprind.org/en/actions/strategic-projects/law-as-code" rel="noopener noreferrer"&gt;Law as Code&lt;/a&gt; as a strategic project aimed at official, machine-readable publication of legal norms.&lt;/p&gt;

&lt;p&gt;Most of this work targets tax and benefits: who is eligible, and for how much. Contract law, time limits and procedure appear less often. The example below is a time limit.&lt;/p&gt;

&lt;h2&gt;
  
  
  A runnable example: when does a limitation period expire?
&lt;/h2&gt;

&lt;p&gt;Article 10.2 of the &lt;a href="https://www.unidroit.org/instruments/commercial-contracts/unidroit-principles-2016/" rel="noopener noreferrer"&gt;UNIDROIT Principles of International Commercial Contracts&lt;/a&gt; (2016 edition) sets two periods. The general limitation period is three years, beginning on the day after the day the obligee knows or ought to know the facts that let it exercise its right. The maximum period is ten years, beginning on the day after the day the right can be exercised.&lt;/p&gt;

&lt;p&gt;Take a case. The obligee learned the facts on 10 March 2020. The right could be exercised from 15 January 2019. Here is the test that sits in the package modelling chapter 10, trimmed to the facts that matter; the full file also names the parties and the contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test "PICCL-01-GENERAL-AND-MAXIMUM-PERIODS" {
    given {
        context {
            deadline_policy PICC_LIMITATION;
            legal_time @2026-09-17;
            timezone "UTC";
        }
        assert "a2": obligee_knew_facts_on(entity_ref("urn:case:piccl:right-1"), @2020-03-10) { origin case_input; }
        assert "a3": right_exercisable_from(entity_ref("urn:case:piccl:right-1"), @2019-01-15) { origin case_input; }
        assert "a4": general_period(entity_ref("urn:case:piccl:right-1"), 3 calendar_year) { origin case_input; }
        assert "a5": maximum_period(entity_ref("urn:case:piccl:right-1"), 10 calendar_year) { origin case_input; }
    }
    evaluate truth(general_period_expires_on(entity_ref("urn:case:piccl:right-1"), @2023-03-11));
    expect truth_status == TRUE_ONLY;
    expect any_applied(GeneralPeriodOfThreeYears);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the case and ask four questions:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Answer&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Is the exercise of this right subject to limitation at all?&lt;/td&gt;
&lt;td&gt;Established&lt;/td&gt;
&lt;td&gt;Article 10.1(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Does the general period expire on 11 March 2023?&lt;/td&gt;
&lt;td&gt;Established&lt;/td&gt;
&lt;td&gt;Article 10.2(1): three years beginning on the day after 10 March 2020&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Does it expire on 10 March 2023?&lt;/td&gt;
&lt;td&gt;Not established&lt;/td&gt;
&lt;td&gt;No rule makes that day the last one&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Does the maximum period expire on 16 January 2029?&lt;/td&gt;
&lt;td&gt;Established&lt;/td&gt;
&lt;td&gt;Article 10.2(2): ten years beginning on the day after 15 January 2019&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The third row is the one to read twice. "Not established" is not "false". The text says the count begins on the day after, so the model says so, and a question about the 10th finds no rule that concludes it. A reader who expected the 10th learns the difference from the model, not from a footnote.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuf7vsoy2ndjjoa1931q7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuf7vsoy2ndjjoa1931q7.png" alt="Article 10.2 as two timelines: the general period runs three years from 11 March 2020, the day after the obligee knew, and expires on 11 March 2023; a question about 10 March 2023 is not established. The maximum period runs ten years from 16 January 2019 and expires on 16 January 2029." width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now the second case: the period has expired, and the obligor has said nothing about it.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Answer&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Is the right extinguished?&lt;/td&gt;
&lt;td&gt;Established: it is not&lt;/td&gt;
&lt;td&gt;Article 10.9(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Is its exercise barred?&lt;/td&gt;
&lt;td&gt;Not established&lt;/td&gt;
&lt;td&gt;Article 10.9(2): the obligor never asserted the expiry&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;May the obligee still set off?&lt;/td&gt;
&lt;td&gt;Established&lt;/td&gt;
&lt;td&gt;Article 10.10: until the expiry is asserted&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two answers that only look contradictory. The right survives, and its exercise is not barred either, because the bar needs an assertion that has not happened. Article 10.10 reads the same silence from the other side.&lt;/p&gt;

&lt;p&gt;There is a third kind of answer. Where the Principles say "could not reasonably" or "fundamentally", the model does not decide. It returns a request for the tribunal's finding, with the article that calls for it. That is what the text asks for, and the answer says so in the same place it would otherwise give a result.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd8cmh82q622cggigqv4p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd8cmh82q622cggigqv4p.png" alt="Three kinds of answer from one evaluation: established, with the article that applied; not established, because no rule concludes it; and a request for the finding the text calls for, addressed to the tribunal or the arbiter." width="799" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Run it yourself.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://picc.law.arxo.io/case-player/limitation/" rel="noopener noreferrer"&gt;Change one fact and watch the answer&lt;/a&gt;: the two cases above, article by article.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://picc.law.arxo.io/date-calculator/limitation/" rel="noopener noreferrer"&gt;Bring your own dates&lt;/a&gt;: articles 10.2 and 10.4 computed in your browser, including acknowledgement, proceedings and impediments.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://picc.law.arxo.io/verify/" rel="noopener noreferrer"&gt;Verify an answer someone sent you&lt;/a&gt;: a saved calculation is run again in your browser, from the same bytes.&lt;/li&gt;
&lt;li&gt;Connect an agent: &lt;code&gt;claude mcp add --transport http picc https://mcp.arxo.io/mcp/picc&lt;/code&gt;, or &lt;code&gt;npx -y @arxo/mcp-picc&lt;/code&gt; for a local server.&lt;/li&gt;
&lt;li&gt;Read the source: &lt;a href="https://github.com/arxohq/arxo-unidroit-picc" rel="noopener noreferrer"&gt;github.com/arxohq/arxo-unidroit-picc&lt;/a&gt;, all 210 articles in seven packages.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What an executable rule carries
&lt;/h2&gt;

&lt;p&gt;Five things travel with every answer above, and they are what makes a rule executable rather than merely encoded.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The text is pinned.&lt;/strong&gt; Each article an answer cites is a fragment of the published text, fixed by a hash of its content. The model is written from that text and points back into it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time is a parameter.&lt;/strong&gt; Every question carries a date. The edition in force on that date answers, and a question asked of the 2024 text and of the 2026 text can get different results with the same facts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Silence and judgment are answers.&lt;/strong&gt; "Not established" means no rule concludes it. "For the tribunal" comes back as a typed request, naming the article that requires the finding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The answer reproduces.&lt;/strong&gt; An answer document holds the request, the chain of reasoning down to the articles, and the hashes of the model and the result. The verify page above runs it again and either matches or shows where it does not.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The rule has tests.&lt;/strong&gt; On 21 September 2026 the corpus of executable canons held 21,948 scenario files like the one above. They are written in one language and fail the way a broken unit test fails. &lt;a href="https://dev.to/arxo/the-law-has-unit-tests-34nc"&gt;The Law Has Unit Tests&lt;/a&gt; walks through one.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The same mechanics beyond the law
&lt;/h2&gt;

&lt;p&gt;A statute, a standard, a rulebook and a textbook share one shape: an authoritative text with an edition and a provenance, applied to facts. Law came first because it is the most demanding case, not because the mechanics stop there.&lt;/p&gt;

&lt;p&gt;Take the &lt;a href="https://handbook.fide.com/chapter/E012023" rel="noopener noreferrer"&gt;FIDE Laws of Chess&lt;/a&gt;, in force since 1 January 2023. Article 7.5.5 says that after a player's first completed illegal move the arbiter gives two minutes to the opponent, and that a second completed illegal move by the same player loses the game, unless the position is such that the opponent cannot checkmate by any possible series of legal moves, in which case the game is drawn.&lt;/p&gt;

&lt;p&gt;Here is the case as the arbiter would record it: White has completed two illegal moves, and the record is complete on whether Black can still mate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;case SecondIllegal {
    assert "player": fide.laws.chess::player_of(entity_ref("urn:example:chess:game"), entity_ref("urn:example:chess:white")) { origin case_input; }
    assert "complete-mate-facts": fide.laws.chess::checked_player(entity_ref("urn:example:chess:white")) { origin case_input; }
    assert "illegal-count": fide.laws.chess::completed_illegal_move_count(entity_ref("urn:example:chess:white"), 2) { origin case_input; }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Case&lt;/th&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Answer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Two illegal moves, mate still possible&lt;/td&gt;
&lt;td&gt;Is the game lost by White?&lt;/td&gt;
&lt;td&gt;Established, by the rule on the second illegal move&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Two illegal moves, no possible mate&lt;/td&gt;
&lt;td&gt;Is the game lost by White?&lt;/td&gt;
&lt;td&gt;Not established&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Two illegal moves, no possible mate&lt;/td&gt;
&lt;td&gt;Is the game drawn?&lt;/td&gt;
&lt;td&gt;Established&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A piece touched, no finding on intent&lt;/td&gt;
&lt;td&gt;Must White move it?&lt;/td&gt;
&lt;td&gt;A request to the arbiter: Article 4 turns on the intention, and the record does not state it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The board, the legality of a move and the possibility of mate are facts of the record. Arxo does not play chess. It applies the Laws to what the arbiter wrote down, and it names the arbiter where the Laws do.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu24jgucxz1cp0x764pl2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu24jgucxz1cp0x764pl2.png" alt="Article 7.5.5 as a decision path over the arbiter's record: one completed illegal move gives Black two minutes; two illegal moves lose the game if Black can still mate and draw it if not; a touch whose intention is not in the record comes back as a request to the arbiter." width="799" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Laws of Chess sit in the same corpus as the Principles and are served at the same public endpoint, &lt;code&gt;https://mcp.arxo.io/mcp&lt;/code&gt;. Next to them: the IFAB Laws of the Game, with the goalkeeper's time limit across two editions; three HTTP RFCs and what happens to a Content-Length header; the CSS cascade from W3C, and which declaration wins. Each is modelled from its pinned text in the same language, and each answers with the section it rests on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Questions people ask
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is Rules as Code the same as Law as Code?&lt;/strong&gt; The same idea under two names. Rules as Code comes from the public-sector community around the New Zealand and OECD work and covers policy and regulation as well as statute. Law as Code is the name used in Germany and in much of the academic literature. Computational law is the broader academic term.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does it replace lawyers or courts?&lt;/strong&gt; No. It computes what follows from the text on the facts supplied. Where the text calls for an assessment, "reasonable", "fundamental", "intended", the answer is a request for that assessment, addressed to the tribunal or the arbiter, with the article that requires it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What tools exist?&lt;/strong&gt; OpenFisca for tax and benefit simulation; Catala, a language whose code follows the structure of the statute; Blawx, a visual tool over answer set programming; and Arxo, where the text is pinned by content, the edition is chosen by date, the answer reproduces by hash, and an AI agent can connect over MCP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I use it from Claude, Cursor or Claude Code?&lt;/strong&gt; Yes. One command adds the Principles as a server: &lt;code&gt;claude mcp add --transport http picc https://mcp.arxo.io/mcp/picc&lt;/code&gt;. The &lt;a href="https://www.arxo.io/mcp/" rel="noopener noreferrer"&gt;MCP page&lt;/a&gt; lists the other endpoints and what an agent can ask.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://blog.arxo.io/what-is-rules-as-code/" rel="noopener noreferrer"&gt;Arxo Writings&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>opensource</category>
      <category>dsl</category>
      <category>testing</category>
    </item>
    <item>
      <title>The Law Has Unit Tests</title>
      <dc:creator>arxo</dc:creator>
      <pubDate>Mon, 05 Oct 2026 19:13:34 +0000</pubDate>
      <link>https://dev.to/arxo/the-law-has-unit-tests-34nc</link>
      <guid>https://dev.to/arxo/the-law-has-unit-tests-34nc</guid>
      <description>&lt;h3&gt;
  
  
  A test of a statute looks like a test of code, with three differences: silence is a passing result, a test can expect a question instead of an answer, and every test carries a date.
&lt;/h3&gt;

&lt;p&gt;Here is a test. If you have ever written one for software, you have read this file before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Law 12.2, 2024/25 edition: the goalkeeper held the ball for nine seconds.
// Date of law 1 September 2024: the 2024/25 book applies.
test "ifab-01-gk-nine-seconds-2024-25" {
    given {
        context { legal_time @2024-09-01; timezone "UTC"; }
        assert "a0": goalkeeper_within_own_penalty_area(match, i1) { origin case_input; }
        assert "a1": goalkeeper_control_seconds(match, i1, 9.0) { origin case_input; }
    }
    evaluate truth(indirect_free_kick_offence(match, i1));
    expect truth_status == TRUE_ONLY;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Given, when, then. Two facts from the match report, one question to the Laws of the Game, one expected answer. The file sits in the &lt;code&gt;tests/&lt;/code&gt; folder of the package that models the IFAB Laws of the Game, next to the rules it exercises. Run it, and Arxo executes the model of Law 12 against these facts and compares the answer with the expectation.&lt;/p&gt;

&lt;p&gt;This is not a metaphor. On 21 September 2026 the corpus of executable canons holds 21,948 such scenario files: contract law, civil codes, insurance statutes, the UN Charter, chess and football, the CSS cascade. They are written in one language, they run under one engine, and they fail the same way a broken unit test fails.&lt;/p&gt;

&lt;p&gt;The interesting part is where a test of a law stops behaving like a test of code.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Silence is a passing result
&lt;/h2&gt;

&lt;p&gt;In software, a function that returns nothing has a bug. In law, a norm that says nothing about your facts is the correct outcome, and a test has to be able to expect it.&lt;/p&gt;

&lt;p&gt;The Declaration by United Nations of 1 January 1942 binds each signatory to employ its full resources against the Axis members "with which such government is at war". The Soviet Union signed. It was at war with Germany and not at war with Japan. Does the Declaration oblige the USSR against Japan?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test "un-test-pair-not-at-war" {
    given {
        context { legal_time @1942-01-01; timezone "Europe/London"; }
        assert "un-war-de2": at_war(UnionOfSovietSocialistRepublics, Germany) { origin case_input; }
    }
    evaluate truth(employs_full_resources_against(UnionOfSovietSocialistRepublics, Japan));
    expect truth_status == NEITHER;
    expect evaluation_status == COMPUTED;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The expected answer is &lt;code&gt;NEITHER&lt;/code&gt;: the proposition is neither established nor refuted. The computation finished (&lt;code&gt;COMPUTED&lt;/code&gt;), nothing went wrong, and the Declaration is simply silent for this pair. The model does not turn missing facts into "false", because the world of a case is open: nobody asserted that the USSR was at war with Japan, and nobody asserted that it was not.&lt;/p&gt;

&lt;p&gt;The same expectation appears in commercial law. Under the UNIDROIT Principles, a non-performance is fundamental if it was intentional, unless the non-performing party would suffer disproportionate loss. A scenario with an intentional breach and a disproportionate loss expects &lt;code&gt;NEITHER&lt;/code&gt; for "fundamental non-performance": the intention does not carry the day, and no other ground was pleaded.&lt;/p&gt;

&lt;p&gt;A test framework that only knows &lt;code&gt;true&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt; cannot express this. The test language for canons has to, or half of the law becomes untestable.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. A test can expect a question
&lt;/h2&gt;

&lt;p&gt;Some elements of a norm are not facts. "Deliberately played the ball", "disproportionate loss", "obvious goal-scoring opportunity": the text hands these to a person with authority to decide. A model that guessed them would be wrong by design. So the model asks, and a test can expect the asking.&lt;/p&gt;

&lt;p&gt;Law 11 of football: a player in an offside position receives the ball from an opponent. Whether the opponent &lt;em&gt;deliberately&lt;/em&gt; played it, or the ball merely rebounded, is the referee's judgement. Without that judgement the question "offside offence?" has no answer yet, and the test says so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test "ifab-07-offside-rebound-requires-judgment" {
    given {
        context { legal_time @2026-09-01; timezone "UTC"; }
        assert "a0": part_in_opponents_half(match, i3, p1) { origin case_input; }
        assert "a2": part_nearer_goal_line_than_second_last_opponent(match, i3, p1) { origin case_input; }
        assert "a4": ball_came_from_opponent(match, i3) { origin case_input; }
        assert "a5": played_or_touched_the_ball(match, i3, p1) { origin case_input; }
    }
    evaluate truth(offside_offence(match, i3, p1));
    expect evaluation_status == REQUIRES_JUDGMENT;
    expect judgment_request(opponent_deliberately_played_the_ball, MatchReferee);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The expectation is precise: the evaluation stops with the status "requires judgement", and the open question is &lt;em&gt;this&lt;/em&gt; predicate, addressed to &lt;em&gt;this&lt;/em&gt; organ, the match referee. Not "the model was unsure". The next scenario in the same folder adds the referee's answer, marked &lt;code&gt;origin adjudicated&lt;/code&gt; rather than &lt;code&gt;origin case_input&lt;/code&gt;, and expects a definite result with zero open questions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5b0e15srm6srbxwr5ppw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5b0e15srm6srbxwr5ppw.png" alt="The judgement channel: without the referee's answer the test expects a named question to the match referee; with it, a definite answer and no open questions." width="799" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The same channel runs through the commercial canons. In the UNIDROIT scenario on fundamental non-performance by deprivation, the expected status is &lt;code&gt;TRUE_ONLY&lt;/code&gt; for the fundamental character &lt;em&gt;and&lt;/em&gt; &lt;code&gt;REQUIRES_JUDGMENT&lt;/code&gt;, because the question of disproportionate loss under Article 7.3.1(2)(e) has not been put to the tribunal. Two expectations on one answer, and both must hold.&lt;/p&gt;

&lt;p&gt;Civil codes use it too. In the Code civil case below, the harmful act, the damage and the causal link are on file: liability under article 1240 comes back as a question for the judge, because it needs a finding of fault, while prescription on the same facts is established, because it needs only dates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://lens.arxo.io/a/b_e249e8e4f3addd78ae9cec3793fc84453e2b698b10d885db86a64d0172c59bda?lang=en" rel="noopener noreferrer"&gt;La faute reste au juge&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Every test carries a date
&lt;/h2&gt;

&lt;p&gt;The file at the top of this article expects an indirect free kick. Its neighbour holds the same two facts and expects a corner kick:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// The same incident on 1 September 2026: the 2026/27 book applies.
test "ifab-02-gk-nine-seconds-2026-27" {
    given {
        context { legal_time @2026-09-01; timezone "UTC"; }
        assert "a0": goalkeeper_within_own_penalty_area(match, i1) { origin case_input; }
        assert "a1": goalkeeper_control_seconds(match, i1, 9.0) { origin case_input; }
    }
    evaluate truth(restart_awarded(match, i1, corner_kick));
    expect truth_status == TRUE_ONLY;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing in the package was edited between the two tests. Both rules live in the model, each pinned to the edition of the Laws that contains it, each edition with its window of force:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@source(LOTG_2425_LAW_12)
rule GoalkeeperSixSecondsIndirectFreeKick(m, i, secs) strict {
    when goalkeeper_within_own_penalty_area(m, i)
        and goalkeeper_control_seconds(m, i, secs)
        and (secs &amp;gt; 6.0);
    then indirect_free_kick_offence(m, i);
}

@source(LOTG_2526_LAW_12, LOTG_2627_LAW_12)
rule GoalkeeperEightSecondsCornerKick(m, i, secs) strict {
    when goalkeeper_within_own_penalty_area(m, i)
        and goalkeeper_control_seconds(m, i, secs)
        and (secs &amp;gt; 8.0);
    then restart_awarded(m, i, corner_kick);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft855vsrfah5gt98br888.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft855vsrfah5gt98br888.png" alt="Same two facts, two dates of law: each date falls into a different edition window and selects a different rule." width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The date of law in the test selects the edition; the edition selects the rule. Of the 21,948 scenarios in the corpus, 19,358 name a date of law explicitly. A test without a date would be a test of "the law in general", and there is no such thing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tests are written from the text, not from the model
&lt;/h2&gt;

&lt;p&gt;A unit test that was generated from the implementation tests nothing: it will agree with whatever the code does. The same trap exists for law, and it is easier to fall into, because the model is often the first precise reading of the text anyone has produced.&lt;/p&gt;

&lt;p&gt;So the rule for canons is the rule for good test suites: the expectation comes from the source, and it is frozen. A change in the model has to &lt;em&gt;break&lt;/em&gt; scenarios; it never rewrites them. When a scenario and the model disagree, the text is opened, the reading is settled, and the losing side is fixed.&lt;/p&gt;

&lt;p&gt;An example of what the text can hide. Article 19(4) of the Kazakh compulsory motor insurance law adds a coefficient of 0.8 "for other towns and settlements in the regions listed in paragraph 3". The table in paragraph 3 lists regions, and it also lists Almaty, Astana and Shymkent, which are cities of republican significance, not regions. A scenario written from the text for "Almaty, other settlement" expects the coefficient &lt;em&gt;not&lt;/em&gt; to apply. A scenario written from the table would expect the opposite. Three independent readers of the text agreed with the first expectation, and that is the one the package holds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Continuous integration for a bill
&lt;/h2&gt;

&lt;p&gt;Once a statute has a test suite, the question every engineer asks becomes available to a legislator: what does this change break?&lt;/p&gt;

&lt;p&gt;Arxo answers it with an impact report. Take the current model of an act and the model of the draft amendment, run every scenario and every declared goal against both, and compare:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;which norms changed in meaning, counted on the structure of the rules rather than on their wording, so that a reworded label with the same logic is reported as no change;&lt;/li&gt;
&lt;li&gt;which scenarios changed their outcome, with the answer before and after;&lt;/li&gt;
&lt;li&gt;which goals the act declares still hold, and which one held before the amendment and fails after it;&lt;/li&gt;
&lt;li&gt;which of the amended norms are executed by no scenario at all.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb9on4amtnafqh8l8c63u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb9on4amtnafqh8l8c63u.png" alt="Impact report: the scenario bank and the declared goals run against the current model and the draft; changed outcomes, broken goals and amended norms no scenario executes are listed." width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That last line is the one a legislator will not get from a reading. The report names it plainly: for those norms, "outcome unchanged" is an absence of observation, not a conclusion. The test suite of a statute has coverage, and the coverage has holes, and the holes are listed.&lt;/p&gt;

&lt;p&gt;The same report runs on the axis of time instead of the axis of drafts: two dates of law, one act, and the scenarios show what the passage of an edition changed for the cases people actually brought.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to look
&lt;/h2&gt;

&lt;p&gt;The UNIDROIT Principles of International Commercial Contracts are published as executable packages at &lt;a href="https://github.com/arxohq/arxo-unidroit-picc" rel="noopener noreferrer"&gt;github.com/arxohq/arxo-unidroit-picc&lt;/a&gt;. Each package carries its &lt;code&gt;tests/&lt;/code&gt; folder; the scenarios on fundamental non-performance quoted above are in the &lt;a href="https://github.com/arxohq/arxo-unidroit-picc/blob/main/packages/unidroit.picc_non_performance/tests/03-termination.lawtest" rel="noopener noreferrer"&gt;termination file of the non-performance package&lt;/a&gt;. Open one, read the facts, and if you believe the Principles answer differently, send the counterexample as an issue in the same repository. That is how a scenario enters the suite.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://blog.arxo.io/the-law-has-unit-tests/" rel="noopener noreferrer"&gt;Arxo Writings&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>programming</category>
      <category>dsl</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
