docs← Back to article

Markdown for LLMs

nb-24 — Neighbor constructs, nine mistakes and three decision tasks

The source Markdown for this article. Copy it into your assistant or download it as a text file.

Download this articlePlain text ↗
# nb-24 — Neighbor constructs, nine mistakes and three decision tasks

Northbridge is fictional. All applicants, fines, fees, registers
and deadlines in this course are synthetic and unofficial.
Northbridge is not a deployed system and nothing here is a claim
about real law. Verified profile: `law 0.1.0`, language `0.2`,
semantics `law.core/0.2`, std `0.2.0` (from `law --version`,
quoted in section 4).

## 1. Situation

Mira audits Dana's first solo file and finds six confusions between
constructs that look alike. Dana wrote `unless` where the file needed
a denial, a `definition` where it needed a `classification`, and a rule
where it needed a `constraint`. She also mixed up a `function` with a
`decision` table, a `procedure` with a `stage`, and three different ways
of getting residency onto the record.

The same file then fails in nine further ways. Six are quiet misuses:
a set that swallows a duplicate payment, a register closed over the
wrong domain, a swapped time axis, a document admitted on no grounds,
a test that expects what the machine never said, and a mix of two
numeric profiles. Three more come from picking the wrong side of a
close pair: excepting an abbreviation, reporting a lifecycle as a
timeless check, and approving on readiness with no recorded act.

Each pair below comes with the tests that tell the neighbors apart,
and each mistake comes with a run that shows its consequence. Three
decision tasks then ask you to choose the construct before running,
on a senior-parking label, an unpaid fee, and a station approval.

Answers use the four truth statuses from
[nb-01: First permit: facts, a rule and a question](/tutorials/northbridge/nb-01-first-permit/).
`TRUE_ONLY` means the statement is established, `FALSE_ONLY` means it
is denied, `NEITHER` means neither side is supported, and `BOTH`
means both sides are supported in conflict.

## 2. Prerequisites

You need [nb-01: First permit: facts, a rule and a question](/tutorials/northbridge/nb-01-first-permit/):
facts, strict and defeasible rules, the four truth statuses, and
`law test` as the way to check a claim. You also need
[nb-03: Exceptions and conflicting rules](/tutorials/northbridge/nb-03-exceptions/):
`unless`, priority and defeaters. This article turns that lesson
into a three-way distinguishing drill.

The payment pair builds on `Money` arithmetic from
[nb-04: The permit fee](/tutorials/northbridge/nb-04-permit-fee/). The register pair needs
closure, the explicit negative, and the silence outside a closed domain
from [nb-06: When the register may stay silent](/tutorials/northbridge/nb-06-register-silence/).
Packages, `pub` visibility and explicit local imports come from
[nb-18: Packages and composition](/tutorials/northbridge/nb-18-packages-composition/), and
numeric kinds with loud refusals from
[nb-23: Numbers and the standard library: every figure the 0.2 machine proves](/tutorials/northbridge/nb-23-numbers-stdlib/).
The sixth mistake reuses that lesson's `Money / Integer` rejection.

New here: no new construct. This article compares constructs you already
met, then catalogues nine ways a file that uses them fails its checks
or silently misleads.

## 3. Minimal example

Each excerpt below keeps byte-exact lines from the cited package file;
whole unrelated rules are cut. Each label names the package, the path,
the line range, and what was cut.

Pair 1 — `unless` removes, denial asserts, defeater only blocks.
Excerpt 1a — defeasible grant with an `unless` escape
(`demo.northbridge.permits`,
`packs/examples/language-demo/permits/package.law`, lines 23–28;
neighboring rules cut).

```law
rule PermitEligibility defeasible {
    for a: Applicant;
    when demo.northbridge.vocabulary::resident(a) and demo.northbridge.vocabulary::vehicle_registered(a);
    then permit_eligible(a);
    unless permit_suspended(a);
}
```

Ann is a resident driver, so the grant rule fires for her — until the
office suspends her permit. Look at the `unless permit_suspended(a)` line:
when that condition holds, the rule simply stops concluding. The suspension
takes the grant away and says nothing in its place; it does not assert
that Ann is ineligible.

Excerpt 1b — denial by negative inference plus its priority
(`demo.northbridge.permits`,
`packs/examples/language-demo/permits/package.law`, lines 30–36
and 43–46; the badge rule between them cut).

```law
rule FinesRefusal defeasible {
    for a: Applicant;
    when outstanding_fines(a);
    then not permit_eligible(a);
}
priority RefusalOverEligibility {
    prefer FinesRefusal over PermitEligibility;
    reason lex_specialis;
}
```

Ann is again a resident driver, but this time she has outstanding fines.
Look at the two things the excerpt keeps: `then not permit_eligible(a)`
asserts the negation, and the priority prefers `FinesRefusal` over
`PermitEligibility`. The fines do not just block the grant; they deny it,
and the priority makes that denial win the conflict.

Excerpt 1c — defeater: support removed, nothing asserted
(`demo.northbridge.permits`,
`packs/examples/language-demo/permits/package.law`, lines 47–51;
surrounding rules cut).

```law
rule FraudBlocksBadge defeater {
    for a: Applicant;
    when fraud_flag(a);
    defeat permit_eligible(a);
}
```

Bob holds a disability badge, so the badge rule would make him eligible —
but his file carries a fraud flag. Look at the `defeat permit_eligible(a)`
line: a defeater removes support without asserting anything. Fraud blocks
the badge path back to silence (`NEITHER`), not to denial (`FALSE_ONLY`).

Pair 2 — definition abbreviates, classification sorts.
Excerpt 2a — exact abbreviation (`demo.northbridge.permits`,
`packs/examples/language-demo/permits/package.law`, lines 53–55;
surrounding rules cut).

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

Ann lives in the central zone, and the file needs a short name for that
combination. Look at the `definition ... exact` header: the name
`central_resident` is exactly its condition — resident plus lives centrally —
no more. Nothing in the file can except it; the abbreviation always means
the same condition.

Excerpt 2b — classification that may not match
(`demo.northbridge.permits`,
`packs/examples/language-demo/permits/package.law`, lines
117–119; relations and neighboring constructs cut).

```law
classification central_senior(a: Applicant) strict {
    when central_resident(a) and large_household(a);
}
```

Bob lives in the outer zone, so he is not a central resident. Look at the
`classification ... strict` header and its single `when` line: sorting checks
whether the case matches, and Bob matches no case. He stays `NEITHER` —
unsorted — where the definition would have been false; silence here means
"no match", never "denied".

Pair 3 — constraint reports, consequence rule derives.
Excerpt 3a — the report that leaves the fact standing
(`demo.northbridge.permits`,
`packs/examples/language-demo/permits/package.law`, lines
133–138; position rules around it cut).

```law
constraint IssuedNeedsFee(a: Applicant) {
    when permit_issued(a);
    require fee_paid(a);
    severity error;
    message "a permit is issued only after the fee is paid";
}
```

Ann's permit is issued but the fee is unpaid, and the file says so
explicitly. Look at the `when`/`require` pair: when issuance holds, the fee
is required, and a missing fee raises an issue. The permit stays issued
(`TRUE_ONLY`), and the violation is reported beside it; the constraint
un-issues nothing.

Excerpt 3b — a rule that derives and detects nothing
(`demo.northbridge.permits`,
`packs/examples/language-demo/permits/package.law`, lines
201–207; the list-counting sibling rule cut).

```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)));
}
```

Ann paid the fee three times, and the ledger must total her payments.
Look at the `then fee_total_set(...)` line with its `collect`: the rule
derives a total from the payment facts. Totals are derived here; no unpaid
fee is ever reported, because a consequence rule detects nothing.

Pair 4 — function computes, decision table routes.
Excerpt 4a — one expression (`demo.northbridge.calculations`,
`packs/examples/language-demo/calculations/package.law`, line
11; decision tables below cut).

```law
pub function permit_fee(months: Integer) -> Money = months * MONTHLY_RATE;
```

Ann applies for three months, and the office multiplies by the monthly
rate. Look at the single expression after `=`: a function computes one value
from its inputs. Three months always cost thirty euro here; there are no
rows and no policy to consult.

Excerpt 4b — rows with a hit policy
(`demo.northbridge.calculations`,
`packs/examples/language-demo/calculations/package.law`, lines
13–18; the remaining tables cut).

```law
pub decision LongTermDiscount(months: Integer) -> Decimal {
    table hit unique {
        when months >= 12 => 20 percent;
        otherwise => 0 percent;
    }
}
```

Ann applies for twelve months, and the office looks up her discount.
Look at the `table hit unique` header and its two rows: the table routes
inputs to outputs, and twelve months match exactly one row. The `unique`
policy would complain about overlaps instead of guessing; routing carries
a policy the function lacks.

Pair 5 — procedure moves on events, stage indexes rounds.
Excerpt 5a — states and the first region
(`demo.northbridge.procedure`,
`packs/examples/language-demo/procedure/package.law`, lines
47–53; the Tech region, joins and transitions cut).

```law
procedure StationApproval(s: Station) {
    state Draft initial;
    state Filed;
    state Review parallel {
        region Docs {
            state DocsPending initial;
            state DocsOk terminal;
```

A charging station waits for its documents while the file sits in review.
Look at the `state DocsPending initial` line inside the `Docs` region: the
case rests there until the `DocsFiled` event moves it. Nothing derives
anything; events move the case, and waiting is the point.

Excerpt 5b — rounds as derivation index
(`demo.northbridge.allocation`,
`packs/examples/language-demo/allocation/package.law`, lines
14–18; relations and seeding rules cut).

```law
stage Allotment {
    index round: Integer from 1 to 2;
    bind shortlisted index 2;
    bind admitted index 2;
}
```

Seat allocation runs in two rounds, and the second round reads the closed
first one. Look at the `index round: Integer from 1 to 2` line: the stage
indexes repeated derivation, and round 2 sees what round 1 fixed. There are
no events and no waiting here, only indexed derivation.

Pair 6 — explicit fact, evidence admission, closure.
Excerpt 6a — the closed register (`demo.northbridge.register`,
`packs/examples/language-demo/register/package.law`, lines
18–24; admission rules below cut).

```law
closure ResidentsFile {
    predicate filed_resident;
    domain on_resident_file;
    snapshot "urn:snapshot:demo-northbridge-residents:2026";
    complete_as_of @2026-01-01T00:00:00Z;
    derive_explicit_negative true;
}
```

Carl is on the residents file but has no record in it, and the office must
close that gap. Look at the `domain` and `derive_explicit_negative true`
lines: closure completes the register, so inside the domain absence becomes
denial (`FALSE_ONLY`). Outside the domain, silence stays silence.

Excerpt 6b — admission through five conjuncts
(`demo.northbridge.register`,
`packs/examples/language-demo/register/package.law`, lines
39–47; the evidence policy below cut).

```law
rule Accept strict {
    for e: Text;
    for d: Text;
    for link: Text;
    when edge(e, d, link) and evidence_status(d, "verified")
        and authentic(d, "urn:demo:northbridge:verifier", "verified")
        and available(d) and current(d);
    then accepted(e);
}
```

A document arrives for Ann, and the office checks it against five conditions
before trusting it. Look at the long `when` with its five conjuncts: the edge,
verified status, pinned authenticity, availability and currency must all hold.
Drop authenticity and the document stays transport; admission needs every
conjunct, not just most of them.

Excerpt 6c — the plain asserted fact
(`demo.northbridge.register`,
`packs/examples/language-demo/register/tests/register.lawtest`,
lines 22–29; the remaining suite cut).

```law
test "file record accepted" {
    given {
        context { legal_time @2026-03-01; decision_time @2026-03-01T09:00:00Z; knowledge_time @2026-03-01T09:00:00Z; timezone "UTC"; }
        assert "filed-ann": filed_resident(entity_ref("urn:demo:northbridge:ann")) { origin case_input; }
    }
    evaluate truth(resident_admitted(entity_ref("urn:demo:northbridge:ann")));
    expect truth_status == TRUE_ONLY;
}
```

Ann's residency is simply asserted on the record, with no document to admit
and no register to walk. Look at the single `assert` line: one fact, entered
directly as case input. The test then asks about her admission and expects
`TRUE_ONLY`; the plain fact needs no policy and no closure.

### Decision task 1 — definition vs classification: the senior-parking label

Northbridge reserves a senior-parking label for residents who live
centrally in big families. Late in the audit, the office adds one demand:
a fraud-flagged applicant must never read as a senior, even when the zone
and family facts qualify them.

Requirements. R1: a qualifying applicant with no fraud flag reads `TRUE_ONLY`.
R2: a non-qualifying applicant reads non-true on a silent record. R3:
a qualifying applicant WITH a fraud flag must not read `TRUE_ONLY`.

Reader prompt. Pick `definition ... exact` or `classification ... defeasible`
for the label. Before running, predict the status of the non-qualifying
applicant under each model, and the status of the qualifying fraud-flagged
applicant under each model. Name the fact that discriminates.

Model A — exact abbreviation (Excerpt from
`demo.northbridge.decisions`,
`packs/examples/language-demo/decisions/package.law`, lines
23–25; the sibling definition and the vocabulary cut):

```law
definition def_senior(a: Applicant) exact {
    when resident(a) and lives_central(a) and big_family(a);
}
```

Ann qualifies on zone and family, and the label abbreviates exactly that.
Look at the `definition ... exact` header: the name is its three-part
condition, and nothing in the file can except it. A fraud flag changes
nothing here, because the definition has no place to hang an exception.

Model B — defeasible sorting plus a defeater (Excerpt from
`demo.northbridge.decisions`,
`packs/examples/language-demo/decisions/package.law`, lines
32–40; the vocabulary cut):

```law
classification cls_senior(a: Applicant) defeasible {
    when resident(a) and lives_central(a) and big_family(a);
}

rule SeniorFraudBlock defeater {
    for a: Applicant;
    when fraud_flag(a);
    defeat cls_senior(a);
}
```

Ann qualifies on zone and family, so the sorting puts her in — until fraud
appears. Look at the `classification ... defeasible` header and the defeater
below it: the case sorts qualifying applicants in, and `SeniorFraudBlock`
takes that support away without asserting anything. Fraud returns the label
to silence, never to denial.

Minimal distinguishing scenario. Give both models identical facts for Ann:
resident, central, big family, plus the fraud flag. The control does NOT
discriminate: resident-only Bob on a silent record stays silent under both
models, so only the fraud flag tells them apart.

### Decision task 2 — constraint vs duty: the unpaid fee

Ann's permit is issued but the fee is unpaid, and the file says so
explicitly. March still allows payment while April means breach, so the
March read and the April read of the same facts must differ.

Requirements. R1: the unpaid issue is flagged on the record. R2: the March
read (payment still possible) differs from the April read (window closed).
R3: the issuance itself stays established on the record throughout.

Reader prompt. Pick a `constraint` that reports beside the standing fact, or
a `rule` deriving an achievement `duty` with a March window. Before running,
predict the issue set and the duty status at the March read and at the April
read under each model.

Model A — the report that leaves the fact standing (Excerpt from
`demo.northbridge.decisions`,
`packs/examples/language-demo/decisions/package.law`, lines
47–52; the duty twin cut):

```law
constraint ConNeedsFee(a: Applicant) {
    when con_issued(a);
    require con_fee(a);
    severity error;
    message "a permit is issued only after the fee is paid";
}
```

Ann's permit is issued and the fee is missing, and the report says so.
Look at the `when`/`require` pair: when issuance holds, the fee is required,
with no window and no lifecycle. The permit stays issued, and the violation
is reported beside it — identically in March and in April.

Model B — a duty with a March window (Excerpt from
`demo.northbridge.decisions`,
`packs/examples/language-demo/decisions/package.law`, lines
60–72; the constraint twin cut):

```law
rule DutyToCollect strict {
    for a: Applicant;
    for o: Office;
    when duty_issued(a) and duty_office(o);
    then duty CollectFee {
        bearer a;
        beneficiary o;
        goal achievement {
            condition duty_fee(a);
            window [@2026-03-01, @2026-03-31];
        }
    };
}
```

Ann's issuance creates an obligation to pay within March. Look at the
`window [@2026-03-01, @2026-03-31]` line and the `achievement` goal: the duty
`CollectFee` carries a March window. The position lifecycle — `ACTIVE`, then
`VIOLATED` — carries the verdict, not an issue.

Minimal distinguishing scenario. Take issued Ann with explicit `not fee_paid`
and the office on file. Read the same record twice: once with
`decision_time @2026-03-10` and once with `@2026-04-10`.

### Decision task 3 — procedure vs stage: approval with and without acts

A charging station is substantively ready: the file is complete and the
nameplate is within limits. Two modelings compete: a procedure that moves
the case through states only on recorded events, and a derivation that
computes the outcome from the substantive facts over indexed rounds. The
office asks what the file may say before anyone acts.

Requirements. R1: a complete, checked, decided file reads approved. R2:
substantive readiness ALONE — no recorded act — must not read approved. R3:
the model states where the case rests while it waits.

Reader prompt. Pick `procedure` (event-gated states) or `stage` (indexed
derivation rounds). Before running, predict what each model says about
approval with all substantive facts present and zero events asserted, and
where the waiting case rests in the procedure.

Model A — states moved by events (Excerpt from
`demo.northbridge.decisions`,
`packs/examples/language-demo/decisions/package.law`, lines
87–103; the event declarations cut):

```law
procedure MiniApproval(s: Station) {
    state Draft initial;
    state Filed;
    state Approved terminal;
    transition File {
        from Draft;
        to Filed;
        on EvFiled;
        when file_complete(s);
    }
    transition Decide {
        from Filed;
        to Approved;
        on EvDecided;
        when nameplate_ok(s);
    }
}
```

The station is ready on paper, but no official has acted yet. Look at the
two transitions: `File` needs `EvFiled` plus a complete file, and `Decide`
needs `EvDecided` plus a sound nameplate. The case waits in a state until an
event moves it; readiness derives nothing by itself.

Model B — rounds as derivation index (Excerpt from
`demo.northbridge.decisions_stage`,
`packs/examples/language-demo/decisions-stage/package.law`,
stage lines 13–17; seeding and relations cut):

```law
stage MiniAllotment {
    index round: Integer from 1 to 2;
    bind shortlisted index 2;
    bind admitted index 2;
}
```

Excerpt — the `Admit` rule
(`packs/examples/language-demo/decisions-stage/package.law`,
lines 32–39; seeding cut):

```law
rule Admit strict {
    for a: Applicant;
    for p: Integer;
    for r: Integer;
    when supported(shortlisted(a, r)) and r < 2 and points(a, p) and p >= MIN_POINTS;
    then admitted(a, r + 1);
}
```

Ann has enough points, and the rounds do the rest. Look at the `Admit` rule:
round 2 reads the closed round 1 and derives admission from points. There are
no events anywhere in this world, so nothing can wait; the outcome follows
from the facts alone.

Minimal distinguishing scenario. Assert all substantive facts and zero
`attempted_transition` facts. The two worlds are separate by construction —
`decisions-stage` has no dependency on `decisions` — so the comparison is
about the input-to-outcome pattern on the same input shape, not about one
shared predicate.

<details>
<summary>Package map for the six pairs</summary>

Pairs 1–3 and the ledger come from `demo.northbridge.permits`; pair 4 from
`demo.northbridge.calculations`; pair 6 from `demo.northbridge.register`; pair 5
from `demo.northbridge.procedure` and `demo.northbridge.allocation`. The decision
tasks use `demo.northbridge.decisions` and `demo.northbridge.decisions_stage`.

</details>

## 4. Command and result

Tool versions first (five facts: tool, language, semantics, std,
binary):

```sh
law --version
```

Observed (exit 0):

```text
law 0.1.0
семантика: law.core/0.2
std для языка 0.2: 0.2.0
хэш бинаря: sha256:78dea06ce928547e87bd9875a2556cc663def37cbb78c8b04aa0da57839c95d7
```

The four lines carry five facts. `law 0.1.0` is the tool; `семантика`
means semantics (`law.core/0.2`); `std для языка 0.2: 0.2.0` names the
language (`0.2`) and its standard library (`0.2.0`); `хэш бинаря` is the
binary hash. These are the versions every run below assumes.

Pair 1–3 plus the payment ledger, one run of the permits world:

```sh
law test packs/examples/language-demo/permits 2>&1 | grep -E "unless|denial wins|defeater|definition|classification|constraint reports|duty violated|set ignores|list counts|итого"
```

Observed (exit 0, suite green):

```text
  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 / defeater removes support without negation
  ok   [demo.northbridge.permits] tests/permits.lawtest / definition: central resident
  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 / 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 violated
итого: 28 проверено, 28 прошли, 0 не прошли, 0 не исполнены; код 0
```

The ten `ok` lines cover pairs 1–3 and the payment ledger. The first three
tell `unless` (suspension back to silence), denial (fines to `FALSE_ONLY`)
and defeater (fraud back to silence) apart. The next three sort the central
resident and the senior household; then come the constraint report, the two
ledger totals, and the violated duty.

The summary `итого: 28 проверено, 28 прошли, 0 не прошли, 0 не исполнены;
код 0` means 28 checked, 28 passed, 0 failed, 0 unexecuted, exit code 0.
A passing test means the answer matched its expectation; it does not mean
every applicant in the file was granted.

<details>
<summary>Why the commands pipe through grep</summary>

Each `law test` run prints its full suite; the `grep` keeps only the lines that
tell the neighbors apart, plus the summary. The summary still reports the whole
suite (28 checked here, not just the ten lines shown).

</details>

Pair 4, the calculations world:

```sh
law test packs/examples/language-demo/calculations 2>&1 | grep -E "fee for three|discount for twelve|итого"
```

Observed (exit 0, suite green):

```text
  ok   [demo.northbridge.calculations] tests/calculations.lawtest / fee for three months
  ok   [demo.northbridge.calculations] tests/calculations.lawtest / discount for twelve months
итого: 9 проверено, 9 прошли, 0 не прошли, 0 не исполнены; код 0
```

The two `ok` lines are the function and the table side by side. Three months
of fee compute to 30 EUR, and twelve months route to the 0.2 discount row.
The summary means 9 checked, 9 passed, 0 failed — the calculations world
is green.

Pair 6, the register world:

```sh
law test packs/examples/language-demo/register 2>&1 | grep -E "on file without|outside the domain|authenticity|policy|итого"
```

Observed (exit 0, suite green):

```text
  ok   [demo.northbridge.register] tests/register.lawtest / on file without a record — not a resident
  ok   [demo.northbridge.register] tests/register.lawtest / outside the domain silence is silence
  ok   [demo.northbridge.register] tests/register.lawtest / policy selected, authenticity pinned
  ok   [demo.northbridge.register] tests/register.lawtest / without pinned authenticity support is rejected
  ok   [demo.northbridge.register] tests/register.lawtest / without a policy support stays transport
  ok   [demo.northbridge.register] tests/register.lawtest / bare assertion of the protected under a policy
итого: 9 проверено, 9 прошли, 0 не прошли, 0 не исполнены; код 0
```

The six `ok` lines walk the three residency routes. The on-file-but-recordless
case is denied by closure, while the outside-domain case stays silent. The
pinned document is admitted through the policy, and the three negative probes
confirm that dropping authenticity, dropping the policy, or asserting the
protected predicate bare all fail to admit.

The summary means 9 checked, 9 passed, 0 failed. For the case at hand, the
route determines the status: asserted fact and pinned document admit Ann,
closure denies Carl inside the domain, and Dana outside it stays `NEITHER`.

Pair 5, two worlds that never meet (allocation depends on
register, never on procedure):

```sh
law test packs/examples/language-demo/procedure 2>&1 | grep -E "join waits|both regions ready|итого"
```

Observed (exit 0, suite green):

```text
  ok   [demo.northbridge.procedure] tests/procedure.lawtest / both regions ready — decision taken
  ok   [demo.northbridge.procedure] tests/procedure.lawtest / join waits for both regions
итого: 6 проверено, 6 прошли, 0 не прошли, 0 не исполнены; код 0
```

The procedure waits as designed: the join holds until both regions are ready,
and the decision is taken only then. The summary means 6 checked, 6 passed —
the waiting behavior, not a derivation, is what this world proves.

```sh
law test packs/examples/language-demo/allocation 2>&1 | grep -E "round 2 admits|insufficient|closed total|итого"
```

Observed (exit 0, suite green):

```text
  ok   [demo.northbridge.allocation] tests/allocation.lawtest / round 2 admits by points
  ok   [demo.northbridge.allocation] tests/allocation.lawtest / insufficient points — no seat granted
  ok   [demo.northbridge.allocation] tests/allocation.lawtest / closed total reads after the rounds
итого: 5 проверено, 5 прошли, 0 не прошли, 0 не исполнены; код 0
```

The allocation derives as designed: round 2 admits by points, insufficient
points grant no seat, and the closed total reads after the rounds. The summary
means 5 checked, 5 passed. Events move the first world; indexes derive the
second — and the two never meet.

Decision tasks 1 and 2, the `decisions` world (both rival
models under distinct names, one run):

```sh
law test packs/examples/language-demo/decisions 2>&1 | grep -E "senior|fraud|negated|unpaid|duty|no report|итого"
```

Observed (exit 0, suite green):

```text
  ok   [demo.northbridge.decisions] tests/decisions.lawtest / probe: defined senior on a silent record
  ok   [demo.northbridge.decisions] tests/decisions.lawtest / probe: classified senior on a silent record
  ok   [demo.northbridge.decisions] tests/decisions.lawtest / probe: fraud against the defined senior
  ok   [demo.northbridge.decisions] tests/decisions.lawtest / probe: fraud against the classified senior
  ok   [demo.northbridge.decisions] tests/decisions.lawtest / probe: qualifying senior without fraud, both models
  ok   [demo.northbridge.decisions] tests/decisions.lawtest / probe: definition over negated atom stays silent
  ok   [demo.northbridge.decisions] tests/decisions.lawtest / probe: issued but unpaid — march read
  ok   [demo.northbridge.decisions] tests/decisions.lawtest / probe: issued but unpaid — april read
  ok   [demo.northbridge.decisions] tests/decisions.lawtest / probe: duty world emits no report
  ok   [demo.northbridge.decisions] tests/decisions.lawtest / probe: fee duty active inside window
  ok   [demo.northbridge.decisions] tests/decisions.lawtest / probe: fee duty violated after window
итого: 14 проверено, 14 прошли, 0 не прошли, 0 не исполнены; код 0
```

The eleven `ok` lines decide the first two tasks. For the senior label, both
models agree without fraud and on a silent record, but fraud leaves the
definition true while silencing the classification. For the unpaid fee, the
constraint flags both reads identically while the duty moves from `ACTIVE`
to `VIOLATED`, and the duty world emits no report.

The summary means 14 checked, 14 passed. Rival models run under distinct names
in one world, so one run compares them without letting their heads compete.

Decision task 3, the event half in the same world:

```sh
law test packs/examples/language-demo/decisions 2>&1 | grep -E "without events|filed chain|итого"
```

Observed (exit 0, suite green):

```text
  ok   [demo.northbridge.decisions] tests/decisions.lawtest / probe: complete file without events - no approval
  ok   [demo.northbridge.decisions] tests/decisions.lawtest / probe: complete file without events - still draft
  ok   [demo.northbridge.decisions] tests/decisions.lawtest / probe: filed chain approves
итого: 14 проверено, 14 прошли, 0 не прошли, 0 не исполнены; код 0
```

The three `ok` lines are a filtered view of the same 14-test suite. The complete
file without events reads no approval and still `Draft`; the filed chain with
both events approves. The summary repeats 14 checked, 14 passed, because the
grep shows three lines of one green run.

And the derivation half in its own world (no shared
dependency, so no stage and no procedure ever meet):

```sh
law test packs/examples/language-demo/decisions-stage
```

Observed (exit 0, suite green):

```text
law test demo.northbridge.decisions_stage: мир demo.northbridge.decisions_stage
  ok   [demo.northbridge.decisions_stage] tests/decisions-stage.lawtest / probe: admission derives without any event
  ok   [demo.northbridge.decisions_stage] tests/decisions-stage.lawtest / probe: insufficient points stay out
итого: 2 проверено, 2 прошли, 0 не прошли, 0 не исполнены; код 0
```

The header `мир demo.northbridge.decisions_stage` names the world under test
(`мир` means world). Admission derives from points with no recorded act
anywhere, and insufficient points stay out. The summary means 2 checked,
2 passed — the derivation half answers from facts alone.

No single run covers both halves of task 3: the stage world has no dependency
on the procedure world, so the comparison is about the input-to-outcome pattern,
not one shared predicate.

The refused repair — bolting a defeater onto a defined head —
fails statically, so it ships as a snippet, not a suite:

```sh
law engine check packs/examples/language-demo/decisions/evidence/snippets/def-head.law.txt
```

Observed (exit 1):

```text
packs/examples/language-demo/decisions/evidence/snippets/def-head.law.txt:13:12: error LDC-E4112: DEFEATER_WITHOUT_CANDIDATE: defeater "Block" атакует positive-голову "lab", но у неё нет defeasible-продюсера (§107.3; DECISION-0111 §2.1)
```

The checker refuses the file before anything runs. `LDC-E4112` with
`DEFEATER_WITHOUT_CANDIDATE` says the defeater attacks a positive head that
has no defeasible producer; the Russian clause says the same (`атакует`
attacks, `но у неё нет` but it has no). Exit 1 is the expected refusal, and
the snippet ships precisely because it cannot join a green suite.

## 5. Why this construct

Each pair proves one behavioral difference. None proves the other side absent.

**Pair 1 — `unless`, denial, defeater.** Ann is suspended in one test, fined
in another, while Bob's badge case carries a fraud flag. The suspended
resident ends `NEITHER` (`unless removes the conclusion`); the fined resident
ends `FALSE_ONLY` (`denial wins by priority`); the fraudulent badge holder
ends `NEITHER` again (`defeater removes support without negation`).

The two `NEITHER`s are not the same fact: suspension blocks one rule, fraud
defeats another, and only the denial asserts a negation that priority can
prefer. The pair does NOT prove fraud is worse than fines — it proves the
machine records three different outcomes for three different shapes.

**Pair 2 — definition, classification.** Ann lives centrally, and with four
household members she also sorts as a central senior. `central_resident`
fires for her (`definition: central resident`); `central_senior` fires for her
too, but matches nothing for Bob from the outer zone (`classification: not
from the centre — no match`, `NEITHER`). The definition would have been false
for Bob; the classification is silent instead.

The pair does NOT prove classifications never deny — it proves non-match here
is silence, not denial. Decision task 1 decides the auditor's file: the
defeasible classification wins. It meets R1 (both models `TRUE_ONLY` without
fraud), R2 (both `NEITHER` on a silent record) and R3 (fraud-flagged Ann reads
`NEITHER` under `cls_senior` but stays `TRUE_ONLY` under `def_senior`).

The definition fits where the name is a pure abbreviation with no exceptions
ever, such as `central_resident` itself. The attempted repair — the same
defeater on the defined head — is refused with `LDC-E4112` because a defined
head has no defeasible producer. This does NOT prove every sorting needs
defeasibility — it proves only that on these facts the exception requires
a defeasible producer.

**Pair 3 — constraint, consequence rule.** Ann's permit is issued but unpaid,
while the office misses its own deadline. The issued-but-unpaid permit stays
`TRUE_ONLY` and carries `CONSTRAINT_VIOLATED` (`constraint reports the
violation`); the late office is `VIOLATED` on its duty (`duty violated`). The
constraint never un-issues the permit; the duty never derives a payment.

The pair does NOT prove every requirement wants a constraint — it proves
reporting and deriving are different jobs. Decision task 2 decides the
March/April file: the duty rule wins. It meets R1 through the lifecycle
(`ACTIVE`, then `VIOLATED`), R2 (the two reads differ) and R3 (issuance stays
`TRUE_ONLY`, and the `no report` probe confirms no issue is emitted). The
constraint meets R1 and R3 but fails R2: March and April read identically.

The constraint fits where the requirement is a timeless invariant with no grace
period — a static "these two may not co-occur" check. This does NOT prove
duties subsume constraints — it proves only that a lifecycle requirement needs
a construct that has one.

**Pair 4 — function, decision table.** Ann pays for three months and asks for
the twelve-month discount. `permit_fee(3)` is `30 EUR` (`fee for three
months`); `LongTermDiscount(12)` is `0.2` (`discount for twelve months`). The
input shape is the same but the machinery differs: the function always
computes, while the table routes and its `unique` policy polices overlaps.

The pair does NOT prove tables compute more — it proves routing carries
a policy the function lacks.

**Pair 5 — procedure, stage.** A station waits for both review regions, while
a seat allocation closes its rounds. The station waits for both regions
(`join waits for both regions`) and decides only when both are ready (`both
regions ready — decision taken`); the allotment admits by points in round 2
(`round 2 admits by points`) and reads the closed total afterwards (`closed
total reads after the rounds`). Events move the first; indexes derive
the second.

The pair does NOT prove stages are simpler — it proves waiting and indexing
answer different questions. Decision task 3 decides the untouched file: the
procedure wins. It meets R1 (the filed chain approves), R2 (the complete file
without events reads `Approved: NEITHER`) and R3 (the case rests in `Draft:
TRUE_ONLY`). The stage meets R1 in its own world but fails R2: substantive
facts alone derive `admitted(ann, 2): TRUE_ONLY` with no recorded act anywhere.

The stage fits where the outcome is pure computation over closed rounds with
no human acts to record. This does NOT prove procedures are always safer — it
proves only that waiting for acts needs a construct that records acts.

**Pair 6 — explicit fact, evidence admission, closure.** Ann reaches the
record twice: once by direct assertion, once by pinned document. The asserted
record admits her (`file record accepted`, via Excerpt 6c); the pinned document
admits her through the policy (`policy selected, authenticity pinned`). The
on-file-but-recordless Carl is denied (`on file without a record — not
a resident`, `FALSE_ONLY` by closure); Dana, outside the domain, is silence
(`outside the domain silence is silence`, `NEITHER`).

One predicate, four routes, three different statuses. The set does NOT prove
documents are unnecessary — it proves each route has its own preconditions.

## 6. Changed condition

Ann is a resident driver and the grant fires for her. Add one hold to her
file and the grant goes silent.
Excerpt — the defeating fact (`demo.northbridge.capstone`,
`packs/examples/language-demo/capstone/tests/capstone.lawtest`,
lines 25–34; the granting sibling test cut).

```law
test "a hold defeats the grant" {
    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-ann": demo.northbridge.vocabulary::resident(entity_ref("urn:demo:northbridge:ann")) { origin case_input; }
        assert "vehicle-ann": demo.northbridge.vocabulary::vehicle_registered(entity_ref("urn:demo:northbridge:ann")) { origin case_input; }
        assert "hold-ann": capstone_hold(entity_ref("urn:demo:northbridge:ann")) { origin case_input; }
    }
    evaluate truth(capstone_grant(entity_ref("urn:demo:northbridge:ann")));
    expect truth_status == NEITHER;
}
```

Look at the three `assert` lines: resident, vehicle, and the added `hold-ann`.
That hold is the only difference from the granting test. Readiness still holds,
but the grant does not.

```sh
law test packs/examples/language-demo/capstone 2>&1 | grep -E "hold|итого"
```

Observed (exit 0, suite green):

```text
  ok   [demo.northbridge.capstone] tests/capstone.lawtest / resident driver is granted without a hold
  ok   [demo.northbridge.capstone] tests/capstone.lawtest / a hold defeats the grant
итого: 9 проверено, 9 прошли, 0 не прошли, 0 не исполнены; код 0
```

The change is one fact: `hold-ann`. The result is a flip from `TRUE_ONLY` in
the granting test to `NEITHER` here, while readiness is untouched. The hold
defeats the grant without denying it, so the case reads silence — not refusal.
The summary means 9 checked, 9 passed; both lines pass because each answer
matched its expectation.

## 7. Typical mistake

Nine mistakes, each with the run that shows it. Each entry names the mistake,
the observed consequence, and the fix.

Mistake 1 — billing from the set. Ann pays 10 EUR three times, and Dana
totals from the set. The mistake is billing from `fee_total_set`: three
payments of 10 EUR collapse to a set total of 10, not 30.

The section 4 permits run shows the consequence: `set ignores duplicates: three
times 10 — total 10` against `list counts duplicates: three times 10 — total 30`.
Bill from the set and the customer is undercharged by 20 EUR with every test
green. Fix: bill from `fee_total_all`, which counts each payment.

Mistake 2 — closing the register over the wrong domain. Dana has no record,
and Dana's absence is what the domain line decides. The mistake is putting her
on the domain: her absence then becomes `FALSE_ONLY`, while outside it stays
`NEITHER`.

The section 4 register run shows the consequence: `on file without a record —
not a resident` against `outside the domain silence is silence`. Carl inside
the domain is denied (`FALSE_ONLY`); Dana outside it is silence (`NEITHER`).
Fix: close the register over exactly the domain the file promises — the domain
line is the whole difference.

Mistake 3 — reading at the wrong time axis. The office reads Ann's reply term,
and the axis it reads on decides the verdict. The mistake is evaluating at
knowledge time: the sources pair decides on `decision_time`, with the same
`knowledge_time` (`@2027-12-31`) in both tests.

The 11 March file is `ACTIVE` (`working days: the term includes the window end`)
while the 12 March file without performance is `VIOLATED` (`working days:
overdue without performance`). Evaluate at knowledge time and the 11 March file
looks overdue a year early. Fix: read the lifecycle at `decision_time`.
Reproduced by the run below:

```sh
law test packs/examples/language-demo/sources 2>&1 | grep -E "window end|overdue|итого"
```

Observed (exit 0, suite green):

```text
  ok   [demo.northbridge.sources] tests/sources.lawtest / working days: the term includes the window end
  ok   [demo.northbridge.sources] tests/sources.lawtest / working days: overdue without performance
итого: 6 проверено, 6 прошли, 0 не прошли, 0 не исполнены; код 0
```

The two `ok` lines differ only by decision day: 11 March still inside the window,
12 March past it without performance. The summary means 6 checked, 6 passed.
For the case at hand, the axis is the verdict — knowledge time sees a year-old
file, decision time sees whether the window has closed.

Mistake 4 — admitting a document on no grounds. Ann's document arrives, and
Dana drops the authenticity conjunct from Excerpt 6b. The mistake is admitting
on four conjuncts out of five: without authenticity, `accepted` never derives.

The section 4 register run shows the consequence: `without pinned authenticity
support is rejected` and `without a policy support stays transport`. Transport
in, transport out, no admission. Fix: keep all five conjuncts and the policy —
admission needs every one of them.

Mistake 5 — expecting what the machine never said. Ann paid once, but the rule
needs two payments. The mistake is a test that demands `TRUE_ONLY` from one
payment: it claims what the machine never said. **This test is meant to fail.**
Reproduced by a scratch probe under `/tmp` (writes stay inside `/tmp`):

```sh
mkdir -p /tmp/nb24-m5 && cat > /tmp/nb24-m5/probe.law <<'EOF'
language "law.core" version "0.2";
package probe version "0.1.0";
namespace "urn:probe";
relation paid(a: Text, n: Integer) kind empirical;
relation ready(a: Text) kind institutional;
rule Ready strict {
    for a: Text;
    when paid(a, 1) and paid(a, 2);
    then ready(a);
}
EOF
cat > /tmp/nb24-m5/probe.lawtest <<'EOF'
language "law.core" version "0.2";
package probe version "0.1.0";
namespace "urn:probe";
test "ready with one payment only" {
    given {
        context { legal_time @2026-03-01; decision_time @2026-03-01T09:00:00Z; knowledge_time @2026-03-01T09:00:00Z; timezone "UTC"; }
        assert "p1": paid("ann", 1) { origin case_input; }
    }
    evaluate truth(ready("ann"));
    expect truth_status == TRUE_ONLY;
}
EOF
law engine test /tmp/nb24-m5/probe.lawtest --program /tmp/nb24-m5/probe.law 2>&1
```

Observed (expected FAIL, exit 1):

```text
test FAIL: ready with one payment only
  truth_status == TRUE_ONLY: в документе NEITHER
lawc test: 0/1 тестов прошли
```

The test fails loudly, as designed. `test FAIL: ready with one payment only`
names the failing test; `в документе NEITHER` means the document holds
`NEITHER` (`в документе` means in the document); `lawc test: 0/1 тестов прошли`
means 0 of 1 tests passed. Silence is not confirmation — one payment leaves
`ready` at `NEITHER`, not `TRUE_ONLY`. Fix: expect `NEITHER`, or supply both
payments before expecting `TRUE_ONLY`.

Mistake 6 — mixing numeric profiles. Dana divides 1000 KZT by 3. The mistake
is the quiet mix: `Money` divided by an `Integer` is refused at check time.

Standalone mix — full content of `mix.law`: the profile mix the checker refuses
(expected refusal, LDC-E2108). **This file is meant to be refused.** The divisor
must be `Decimal`.

```law
language "law.core" version "0.2";
package probe version "0.1.0";
namespace "urn:probe";
pure function quarter() -> Money = 1000 KZT / 3;
```

Look at the `-> Money` promise and the `/ 3` divisor: the arrow promises
`Money`, but the divisor is an `Integer`. The kind discipline refuses the file
before anything runs; money has no quiet integer division.

Reproduced by checking the scratch probe. Save the block above as
`/tmp/nb24-m6/mix.law` first (create the directory if needed), then run:

```sh
law engine check /tmp/nb24-m6/mix.law 2>&1
```

Observed (expected refusal, exit 1):

```text
/tmp/nb24-m6/mix.law:4:36: error LDC-E2108: «/»: §58 не называет делимым Money на Integer — виды делимых перечислены поимённо (errata E-0020)
```

The checker refuses the file with `LDC-E2108`: [§58](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/09-part-ix-values-terms-expressions.ru.md#58-arithmetic) does not name `Money`
divided by `Integer` among its dividend kinds (`не называет делимым` means
does not name as dividend; kinds are listed by name, with errata E-0020).
Exit 1 is the expected refusal — no quiet integer division of money happens,
because the file never runs. Fix: use a `Decimal` divisor.

Mistake 7 — excepting an abbreviation. The senior label is defined exactly,
and the fraud exception arrives late with nowhere to attach. The mistake is
bolting the defeater onto the defined head: it is refused statically with
`LDC-E4112`, no defeasible producer.

The section 4 refusal run shows the consequence: the snippet fails `law engine
check` with exit 1, while the classified twin absorbs the same defeater and the
suite stays green. Fix: re-sort the label as a defeasible classification before
fraud can take support away.

Mistake 8 — reporting a lifecycle as a timeless invariant. Ann's permit is
issued but unpaid, and the file must tell March from April. The mistake is
using a constraint: it flags the issue but cannot record that the window has
closed — both reads carry the identical issue with no before/after in the report.

The section 4 march/april runs show the consequence: the `march read` and `april
read` probes each carry their issue, while the duty lifecycle moves from `ACTIVE`
to `VIOLATED`. Pick the constraint and the grace period exists only in the office
manual, never in the record. Fix: use a duty with a window when the requirement
has a lifecycle.

Mistake 9 — approving on readiness with no act. The station is substantively
ready, and Dana treats that readiness as approval. The mistake is deriving the
verdict from facts alone: substantive facts derive `admitted(ann, 2)` in the
stage world, approving a station no official ever touched.

The section 4 runs show the consequence: the decisions-stage run (`admission
derives without any event`) against the decisions event-half run (`complete file
without events — no approval`, `still draft`). Same input shape, opposite
verdicts, because only the procedure records acts. Fix: use a procedure with
event-gated states when approval needs a recorded act.

## 8. Limits

Neighbors share shapes, never semantics. Swapping one for the other compiles —
except the numeric mix, which is refused — and changes the recorded outcome.

The `unless`/denial/defeater three-way, the definition/classification
silence-vs-denial split, and the closure-domain boundary are properties of this
build's four-valued evaluation, not language-wide necessity claims. Verified
profile: `law 0.1.0`, `law.core/0.2`, std `0.2.0`. Refusals (`LDC-E2108` and
`LDC-E4112`) are implementation facts of this profile. Nothing here covers real
registers, real deadlines, or real evidence law.

The decision tasks keep rival models apart by construction. Tasks 1–2 run under
distinct predicate names inside `demo.northbridge.decisions`, and task 3 splits
the procedure from the stage into two worlds with no shared dependency. Rival
heads never compete on one predicate, and no single run covers both worlds.

Window readings are `decision_time` reads of one record, not re-executions. The
`audit_hold` relation exists for the exercise only: no rule names it, so it can
neither sort nor defeat until you write the rule that does.

## 9. Exercise

Bob holds a badge and carries fines, lives in the outer zone, and pays the fee
three times at 10 EUR. For `demo.northbridge.permits`, predict the truth status
of `permit_eligible(Bob)`, the truth status of `central_senior(Bob)`, and the two
ledger totals `fee_total_set` / `fee_total_all` for his three payments. Then check
each prediction against the suite's tests.

Checkable expectation: name all four values before running. All four are confirmed
by `law test packs/examples/language-demo/permits` with 28 passed and 0 failed.
Solution lives ONLY in `solutions/nb-24-solutions.md`.

Decision exercise 1 — the hold nobody wrote. Cora is resident, central, big
family — and carries `audit_hold`, which no rule in `decisions` mentions.
Predict `def_senior(cora)` and `cls_senior(cora)` before running, then check both
on a scratch copy of the package. Copy the package under `/tmp`, add one probe,
and run `law test` on the copy; the shipped suite stays untouched.

Then argue, in one paragraph each: which construct fits a temporary hold that must
never deny the underlying label, and what would have to change for Cora to read
`NEITHER` on `cls_senior`.

Decision exercise 2 — the window opening. Keep the issued-but-unpaid Ann and read
the duty world at `decision_time @2026-03-01` (the window opening) instead of
March 10. Predict the duty status and check it on a scratch copy. Explain in one
paragraph why this reading differs — or does not differ — from the March 10 read.

Then state which construct you would keep if the office abolished the window and
demanded same-day payment, and why.

Decision exercise 3 — the half-filed station. Assert `EvFiled` for the complete
station but no `EvDecided`, and predict the truth status of `Draft`, `Filed` and
`Approved` before running. Check on a scratch copy: copy the `filed chain` probe
and drop the second event. Explain in one paragraph where the case rests now and
which transition is still gated.

Then state what a round-3 extension of `MiniAllotment` could never express about
this waiting.

## 10. Sources

Three levels, separated. In Northbridge, the pairs decide Ann's eligibility,
fines, fraud, household size and the three-times-10 ledger; the decision tasks
decide the senior label, the unpaid fee, and the station approval. As domain
templates, each pair names its reusable shape: blocking vs denying vs defeating,
abbreviating vs sorting, reporting vs deriving, computing vs routing, waiting on
events vs indexing rounds, and the three residency routes.

Full sources: the packages
[permits package](https://github.com/arxohq/law/blob/master/packs/examples/language-demo/permits/package.law),
[calculations package](https://github.com/arxohq/law/blob/master/packs/examples/language-demo/calculations/package.law),
[register package](https://github.com/arxohq/law/blob/master/packs/examples/language-demo/register/package.law),
[procedure package](https://github.com/arxohq/law/blob/master/packs/examples/language-demo/procedure/package.law),
[allocation package](https://github.com/arxohq/law/blob/master/packs/examples/language-demo/allocation/package.law),
[sources package](https://github.com/arxohq/law/blob/master/packs/examples/language-demo/sources/package.law),
[capstone package](https://github.com/arxohq/law/blob/master/packs/examples/language-demo/capstone/package.law),
[decisions package](https://github.com/arxohq/law/blob/master/packs/examples/language-demo/decisions/package.law),
[decisions-stage package](https://github.com/arxohq/law/blob/master/packs/examples/language-demo/decisions-stage/package.law)
and their tests. The scratch probes in section 7 are self-contained under `/tmp`
and need no source.

- Unless/denial/defeater, definition/classification, constraint, set-vs-list
ledger → `demo.northbridge.permits`: Ann's eligibility, fines, fraud, household
size and the three-times-10 ledger.
- Function and decision-table routing → `demo.northbridge.calculations`.
- Closure, admission conjuncts, explicit facts → `demo.northbridge.register`;
time axes and policies → `demo.northbridge.sources`; events and joins →
`demo.northbridge.procedure`; indexed rounds → `demo.northbridge.allocation`.
- Rival-model decision tasks → `demo.northbridge.decisions` (tasks 1–2 and the
procedure half of task 3) and `demo.northbridge.decisions_stage` (the stage half
of task 3, a separate world by construction). The refused defeater-on-definition
repair is pinned as `decisions/evidence/snippets/def-head.law.txt` with its
expected `LDC-E4112`.

No external formalization is claimed for the pair semantics. The four-valued
outcomes are this build's evaluation behavior on the cited fixtures, and this
build executes the 0.2 line only.

<details>
<summary>Scope of the recorded runs</summary>

Each recorded run confirms behavior on its cited fixture under the verified
profile. It does not establish deployment, legal validity, or behavior on
other inputs.

</details>