Skip to content
docs
Arxo ↗

nb-05 — Who counts as a suitable applicant

For LLMs10 sections
← Course mapChapter 05 / 25 · Intermediate

Northbridge course, intermediate (nb-01 → nb-02 → nb-03 → nb-04 → nb-05). Northbridge is synthetic: every act, district, household and payment below is fictional and unofficial, and nothing here claims real municipal deployment or legal validity. Engine law 0.1.0, semantics law.core/0.2, std 0.2.0.

The Northbridge permit office keeps a priority shortlist called suitable applicant: a central-district resident from a large household is offered the first free appointment. Meanwhile the cashier totals fee payments, and the ledger is messy — Ann’s three identical 10 EUR instalments were recorded as three separate receipts.

Two questions reach the same desk: who belongs to the group, and what was actually paid? This article turns both into Law DSL constructs: a definition (a named shorthand for a condition), a classification (a label attached when conditions hold), and aggregates (count and sum folding a collection into one value) — including the Set-versus-List pair that decides whether identical payments are merged or added up.

nb-01: First permit: facts, a rule and a question: facts, one rule, one question, and law test as the way to check a claim. nb-04: The permit fee: Money values such as 10 EUR, and the shared constant LARGE_HOUSEHOLD (the integer 4, defined once in the calculations package and reused here).

Everything below either asks a truth question (does the label hold?) or computes a value (how many? how much?) and stores it in a relation — no duties, evidence, or time machinery is required.

Excerpt 1 — from packs/examples/language-demo/permits/package.law (lines 53–55; imports, relations and the other rules cut):

Arxo Law
definition central_resident(a: Applicant) exact {
when demo.northbridge.vocabulary::resident(a) and demo.northbridge.vocabulary::lives_in(a, demo.northbridge.vocabulary::central);
}

A definition gives a shorthand name to a condition. exact means the name holds exactly when the body holds: resident and living in the central district, nothing more, nothing less. In the code, when carries the full condition — two facts about a, joined by and — while the header names the shorthand.

Excerpt 2 — from the same file (lines 57–62; surrounding rules cut):

Arxo Law
rule LargeHousehold strict {
for a: Applicant;
when demo.northbridge.vocabulary::resident(a)
and count(collect m: Applicant where demo.northbridge.vocabulary::household_member(a, m)) >= demo.northbridge.calculations::LARGE_HOUSEHOLD;
then large_household(a);
}

collect m: Applicant where ... gathers every household member of a into a Set: each distinct member appears once. count(...) is an aggregate — it folds the whole collection into one number — and the rule compares it against the shared threshold 4. Follow the when condition: the collection, the count, and the comparison with LARGE_HOUSEHOLD all sit in that one clause.

Excerpt 3 — from the same file (lines 117–119; presumptions and fictions cut):

Arxo Law
classification central_senior(a: Applicant) strict {
when central_resident(a) and large_household(a);
}

A classification attaches a group label when its body holds. Here it stacks the two previous constructs: the definition plus the aggregate rule. central_senior is the article’s “suitable applicant”. Its body holds just two names — the shorthand and the rule conclusion do all the work defined above.

Excerpt 4 — from the same file (lines 201–215; position rules cut):

Arxo Law
rule FeeTotalSet strict {
for a: Applicant;
for k: Integer;
for v: Money;
when fee_payment(a, k, v);
then fee_total_set(a, sum(collect w: Money, j: Integer where fee_payment(a, j, w)));
}
rule FeeTotalAll strict {
for a: Applicant;
for k: Integer;
for v: Money;
when fee_payment(a, k, v);
then fee_total_all(a, sum(collect all w: Money, j: Integer where fee_payment(a, j, w)));
}

Same three premises, same sum aggregate — one keyword apart. collect builds a Set (identical entries merged); collect all keeps every entry, duplicates included (List behavior). Compare the two rules line by line: apart from their names, the collect versus collect all inside sum(...) is the only difference. The next section shows the observable result: 10 EUR versus 30 EUR on identical input.

The permits package is checked with one command:

Terminal
law test packs/examples/language-demo/permits

Observed result (engine law 0.1.0):

Output
law test demo.northbridge.permits: мир demo.northbridge.permits, demo.northbridge.calculations, demo.northbridge.vocabulary
ok [demo.northbridge.permits] tests/permits.lawtest / general rule: resident with a car
ok [demo.northbridge.permits] tests/permits.lawtest / unless removes the conclusion
ok [demo.northbridge.permits] tests/permits.lawtest / denial wins by priority
ok [demo.northbridge.permits] tests/permits.lawtest / without priority the conflict persists
ok [demo.northbridge.permits] tests/permits.lawtest / defeater removes support without negation
ok [demo.northbridge.permits] tests/permits.lawtest / definition: central resident
ok [demo.northbridge.permits] tests/permits.lawtest / aggregate: large household
ok [demo.northbridge.permits] tests/permits.lawtest / decision term: 30 days
ok [demo.northbridge.permits] tests/permits.lawtest / without a policy the term is not computed
ok [demo.northbridge.permits] tests/permits.lawtest / fee for three months
ok [demo.northbridge.permits] tests/permits.lawtest / positions: duty and prohibition active
ok [demo.northbridge.permits] tests/permits.lawtest / classification: central resident from a large household
ok [demo.northbridge.permits] tests/permits.lawtest / classification: not from the centre — no match
ok [demo.northbridge.permits] tests/permits.lawtest / presumption holds by default
ok [demo.northbridge.permits] tests/permits.lawtest / evidence rebuts the presumption
ok [demo.northbridge.permits] tests/permits.lawtest / fiction: notice deemed received
ok [demo.northbridge.permits] tests/permits.lawtest / constraint reports the violation
ok [demo.northbridge.permits] tests/permits.lawtest / set ignores duplicates: three times 10 — total 10
ok [demo.northbridge.permits] tests/permits.lawtest / list counts duplicates: three times 10 — total 30
ok [demo.northbridge.permits] tests/permits.lawtest / duty satisfied
ok [demo.northbridge.permits] tests/permits.lawtest / duty violated
ok [demo.northbridge.permits] tests/permits.lawtest / outcome unknown — no violation
ok [demo.northbridge.permits] tests/permits.lawtest / maintenance holds while the window is open
ok [demo.northbridge.permits] tests/permits.lawtest / maintenance violated by counterexample
ok [demo.northbridge.permits] tests/permits.lawtest / without a certificate the post-window outcome is unknown
ok [demo.northbridge.permits] tests/permits.lawtest / power exercised lawfully
ok [demo.northbridge.permits] tests/permits.lawtest / power without grounds does not operate
ok [demo.northbridge.permits] tests/permits.lawtest / liberty and immunity
итого: 28 проверено, 28 прошли, 0 не прошли, 0 не исполнены; код 0

The package also passes the static check:

Terminal
law engine check packs/examples/language-demo/permits/package.law
Output
check OK: packs/examples/language-demo/permits/package.law

Six of the 28 tests carry this article:

TestEvaluatesExpects
definition: central residentcentral_resident(ann)TRUE_ONLY
aggregate: large householdlarge_household(ann), 4 membersTRUE_ONLY
classification: central resident from a large householdcentral_senior(ann)TRUE_ONLY
classification: not from the centre — no matchcentral_senior(bob), outer zoneNEITHER
set ignores duplicates: three times 10 — total 10fee_total_set(ann, 10 EUR)TRUE_ONLY
list counts duplicates: three times 10 — total 30fee_total_all(ann, 30 EUR)TRUE_ONLY

Ann is resident, lives in the centre, and has four recorded household members (m1–m4), so the definition holds, the count reaches the threshold of 4, and the classification fires. Bob lives in the outer zone, so the classification body fails — and the answer is NEITHER (no label derived), not a refusal (see nb-02: Why a missing fact is not a refusal for the status meanings).

The last two rows decide the cashier’s question: the same three receipts total 10 EUR under Set collection and 30 EUR when duplicates are kept. The “Changed condition” section unpacks why.

All 28 tests pass: every answer matched its expectation. The summary is in Russian: 28 checked, 28 passed, 0 failed, 0 skipped, exit code 0. The first line names the worlds under test (мир is “world”): the permits package together with the calculations and vocabulary packages it reads.

The task is to decide group membership from combinations of conditions (district plus household size), and to fold repeated records into totals where duplicates may or may not count. A definition names one reusable condition instead of repeating the conjunction in every rule; a classification stacks such conditions into one group label; an aggregate turns “how many / how much” into a value the rule can compare or store. Each does exactly one of the three jobs.

Writing the district conjunction inline in every rule computes the same truth but duplicates the condition — one district rename then touches every rule. Writing the household-size check as four separate member premises cannot express “at least four” without enumerating combinations; count states the threshold directly. Totalling payments with one shared receipt fact instead of three cannot distinguish “paid once” from “paid three times”.

The proof is the six tests above — each membership verdict and each total is executed by law test, including the pair that differs only in the collector keyword (10 EUR vs 30 EUR). What they do not prove: that central-district large households deserve priority, or that three receipts mean three real payments. The tests prove the machine classifies and totals the recorded facts as declared; they say nothing about office policy or the honesty of the ledger. All persons and payments are fictional data.

Change one keyword: collect → collect all. The input is identical in both tests — three fee_payment facts, each 10 EUR, differing only in receipt number (1, 2, 3):

  • fee_total_set(ann, 10 EUR) is TRUE_ONLY: the Set collector merges the three identical 10 EUR entries into one, and sum folds a single entry — total 10 EUR.
  • fee_total_all(ann, 30 EUR) is TRUE_ONLY: the duplicate-preserving collector keeps all three entries, and sum adds 10 + 10 + 10 — total 30 EUR.

Same facts, same aggregate function, different collector, different total — and the test names state the semantics outright (“set ignores duplicates”, “list counts duplicates”).

Totalling repeatable payments with a plain collect. A newcomer copies the household-count pattern (count(collect ...), where Set semantics is correct — four distinct members are four members) into the cashier’s sum. The observable consequence: three recorded 10 EUR instalments total 10 EUR instead of 30 EUR, and the office would credit Ann one third of what she paid.

The fix is to match the collector to the question. Set collection answers “which distinct things exist?” (members, districts, categories) — use plain collect. Adding up events that may repeat (payments, deliveries, readings) needs collect all, or duplicates silently vanish. When in doubt, write the pair as this package does — one rule per collector — and let the two tests disagree loudly.

  • Shorthands derive, they do not evidence. A definition and a classification restate given facts under a new name; neither creates evidence nor overrides a missing fact. Bob’s NEITHER is absence of a label, not a verdict against him.
  • Aggregates need bound collections. count and sum fold the stated where selection — members of one applicant, payments of one applicant — never the whole register. An unbound or wrongly scoped selection folds the wrong rows, and no warning repairs the scope.
  • sum over Money keeps the currency. 10 + 10 + 10 EUR is 30 EUR, exactly (cf. nb-04: The permit fee); mixed currencies do not silently merge.
  • Verified profile: engine law 0.1.0, semantics law.core/0.2, std 0.2.0. Set-versus-duplicate-preserving behavior is a fact about this implementation, not a claim about collection semantics in every language.

Without running the engine, predict, then check with law test:

  1. Ann is a central resident with four recorded household members. What is the status of truth(central_senior(ann)), and which two package elements must both hold for it?
  2. Bob is a resident living in the outer zone. What is the status of truth(central_senior(bob)) — TRUE_ONLY, FALSE_ONLY, NEITHER, or BOTH — and which test name confirms it?
  3. Three receipts of 10 EUR each: what does the Set collector total, and what does the duplicate-preserving collector total? Which two test names pin the two numbers?
  4. Ann pays 10 EUR twice (two receipts) instead of three times. What would the two totals become, and why does the Set total stay unchanged while the other moves?

Write down each prediction first; run the suite for questions 1–3 and explain any miss in one sentence. Question 4 has no suite test — answer it by reasoning from the Set-vs-collect all rule, then compare with the checkable solution: the nb-05 solution.

  • Teaching package: packs/examples/language-demo/permits/package.law (definition central_resident, rule LargeHousehold, classification central_senior, rules FeeTotalSet, FeeTotalAll; threshold LARGE_HOUSEHOLD from packs/examples/language-demo/calculations/package.law).
  • Scenarios: packs/examples/language-demo/permits/tests/permits.lawtest (definition: central resident, aggregate: large household, classification: central resident from a large household, classification: not from the centre — no match, set ignores duplicates: three times 10 — total 10, list counts duplicates: three times 10 — total 30).
  • Level 1 — Northbridge use: this article (fictional priority shortlist and fee ledger).
  • Level 2 — domain template: when group membership combines a place condition with a size threshold, name the place with a definition, count the members with a Set aggregate, and stack both under one classification; when totalling repeatable events, sum with collect all and keep a Set-collector rule beside it wherever distinctness (rather than volume) is the question.
  • Level 3 — confirmed external formalization: guardian’s transactions for an incapacitated person (Civil Code of Kazakhstan, art. 26(2)) — package kz.corpus.civilcode, corpus/laws/kz/codes/civil-code/02b-opeka-i-popechitelstvo.law:121-137, construct entitlement lowered to a conditional power (SovershatSdelkiOtImeniNedeesposobnogo with holder/over/exercise/ effect/valid_when). A person-class consequence gated by conditions, with every head variable bound in the rule body — the same quantified-rule discipline as LargeHousehold and the fee-total rules; and no duty to transact exists, so the entitlement is a conditional power, not an obligation.
Evidence and scope of the external example

Documented in docs/research/constructs/14-claim-entitlement-correlatives/corpus-forms.en.md, section 2 (rated exemplary there). Verification confirms the named construct at the cited lines only, by direct source read; it claims nothing about deployment, runtime behavior, or legal correctness.

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

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