docs← Back to article

Markdown for LLMs

Exercise 10. The same date via two norms

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

Download this articlePlain text ↗
# Exercise 10. The same date via two norms

An exercise for the [from article text to
norm](/tutorials/real-article-rules/) page. On the page the benefit grant
date is computed by one term: `max(from, registered)`. The same meaning
can be written as two norms with guards, a record closer to the article
text, where two cases are named apart.

**Setup.** Replace the one `max` norm with two norms: if disability was
established no earlier than the application registration, benefit is
granted from the establishment date; if earlier, from the registration
date. On all three cases the answer must match the `max` form:

| Established | Application registered | Grant date |
|---|---|---|
| 15 January 2026 | 10 March 2026 | 10 March 2026 |
| 10 March 2026 | 15 January 2026 | 10 March 2026 |
| 10 March 2026 | 10 March 2026 | 10 March 2026 |

**Hint.** The third row is the boundary. One of the two norms must take
equality, and only one: two norms with one head and one value would give
the same answer, but sloppily.

Below is the solution. Try it yourself first.

## Solution

```law
language "law.core" version "0.2";
package tutorial.kz.social version "0.2.1";
namespace "urn:law:tutorial:kz:social";

entity Actor;
entity Person : Actor;
entity DisabilityStatus;
entity Benefit;
entity BenefitApplication;

const DisabilityBenefit: Benefit = entity_ref("urn:law:tutorial:kz:social#DisabilityBenefit") {
    label ru-KZ official "Пособие по инвалидности";
};

relation disability_established(person: Person, status: DisabilityStatus, from: Date) kind institutional;
relation entitled(person: Person, benefit: Benefit) kind institutional;
relation application_for(application: BenefitApplication, person: Person, benefit: Benefit) kind empirical;
relation application_registered(application: BenefitApplication, day: Date) kind institutional;
relation benefit_start_date(person: Person, benefit: Benefit, day: Date) kind institutional;
```

The label reads: "Disability benefit".

Two norms. Equality goes to the first:

```law
@source("KZ-SOCIAL-CODE-224-VII-ART-175")
rule DisabilityBenefitStartFromDisability strict {
    label ru-KZ official "Статья 175. Назначение с даты установления инвалидности";
    for person: Person;
    for status: DisabilityStatus;
    for from: Date;
    for application: BenefitApplication;
    for registered: Date;
    when entitled(person, DisabilityBenefit)
        and disability_established(person, status, from)
        and application_for(application, person, DisabilityBenefit)
        and application_registered(application, registered)
        and from >= registered;
    then benefit_start_date(person, DisabilityBenefit, from);
}

@source("KZ-SOCIAL-CODE-224-VII-ART-175")
rule DisabilityBenefitStartFromApplication strict {
    label ru-KZ official "Статья 175. Назначение с даты регистрации заявления";
    for person: Person;
    for status: DisabilityStatus;
    for from: Date;
    for application: BenefitApplication;
    for registered: Date;
    when entitled(person, DisabilityBenefit)
        and disability_established(person, status, from)
        and application_for(application, person, DisabilityBenefit)
        and application_registered(application, registered)
        and from < registered;
    then benefit_start_date(person, DisabilityBenefit, registered);
}
```

The labels read: "Article 175. Grant from the disability establishment date" and "Article 175. Grant from the application registration date".

Which form is better. `max` is shorter and has no boundary to lose. Two
norms read as the article's two cases and each gets its label: in
verbalisation and in the derivation explanation, the answer's consumer
will see **which** case fired. Both forms are correct; the choice is
about what matters more to show the answer's reader.

## Check

The setup's three rows execute on this package. The fourth
check is a counterfactual: without the `and from >= registered` guard,
the first norm grants benefit from the establishment date on the first
case too. The answer to the 10 March question stays `TRUE_ONLY`, but the
15 January question also answers `TRUE_ONLY`: one person holds two grant
dates at once. A key over person and benefit does not catch this: it
reconciles case facts, not norm conclusions, and declares no conflict.
This page's first version promised `BOTH` here, and the check corrected
it.

What the exercise teaches. Two norms' guards must cover the axis without
gaps or overlaps: `>=` and `<`. A gap yields `NEITHER` on the boundary,
an overlap two values the engine silently holds side by side. The
compiler sees neither mistake; only a boundary case and a **wrong**-date
question catch them.