docs← Back to article

Markdown for LLMs

Exercise 1. A second article of the rules

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

Download this articlePlain text ↗
# Exercise 1. A second article of the rules

An exercise for the [first package](/tutorials/first-package/) page. The
page's package knows one article of the archive rules: the fourth, on the
rare-collections room. The pinned text also holds the third:

```text
Статья 3. Общий читальный зал

Читатель, состоящий в реестре исследователей, допускается в общий читальный
зал в часы работы архива.
```

The quoted article reads: "Article 3. General reading room. A reader listed in the researcher registry is admitted to the general reading room during the archive's opening hours."

**Setup.** Extend the package so that a reader who is listed in the
registry but holds no accreditation gets `TRUE_ONLY` on the question "is
she admitted to the general reading room" and still `NEITHER` on the
rare-collections room question. You need a relation, a fragment of the
third article with the correct `content_hash`, and a norm anchored to
that fragment.

**Hint.** The hash counts over the text bytes between the triple quotes,
including the line break before the closing quotes. The compiler will not
accept someone else's hash and will name the real one in the error
message. That is the way to check yourself.

Below is the solution. Try it yourself first.

## Solution

The header, ontology, and source stay from the first page; one relation
is added:

```law
language "law.core" version "0.2";
package tutorial.archive version "0.1.1";
namespace "urn:law:tutorial:archive";

entity Person;

relation in_researcher_registry(p: Person) kind institutional;
relation accredited(p: Person) kind institutional;
relation may_enter_rare_room(p: Person) kind institutional;
relation may_enter_reading_room(p: Person) kind institutional;

source ARCHIVE_RULES {
    kind municipal_act;
    jurisdiction VELIKY_USTIN;
    number "2026-14";
}

edition ARCHIVE_RULES_2026_RU of ARCHIVE_RULES {
    language ru;
    officiality official;
    adopted @2026-01-15;
    in_force [@2026-02-01, infinity);
}
```

The third article's fragment. The hash below is the real one, and the
check breaks it on purpose to make sure the compiler catches
substitution:

```law
fragment ARCHIVE_RULES_P3 in ARCHIVE_RULES_2026_RU {
    kind paragraph;
    locator "paragraph/3";
    text ru official """Читатель, состоящий в реестре исследователей, допускается в общий читальный
зал в часы работы архива.
""";
    content_hash "sha256:31066ae67f357a39a71fdff3f1c4f68df62afc9f380810456917c3caa3c41601";
}

fragment ARCHIVE_RULES_P4 in ARCHIVE_RULES_2026_RU {
    kind paragraph;
    locator "paragraph/4";
    text ru official """Читатель допускается в зал редких фондов, если он состоит в реестре
исследователей и имеет действующую аккредитацию.
""";
    content_hash "sha256:7f76a4311e52b9af58fcf3175f613794316583ae19c4f0767d0570774a456688";
}
```

The quoted fragments read: "A reader listed in the researcher registry is admitted to the general reading room during the archive's opening hours" and "A reader is admitted to the rare-collections room if listed in the researcher registry and holding a valid accreditation."

Two norms, each on its own anchor:

```law
@source(ARCHIVE_RULES_P3)
rule GeneralReadingRoom strict {
    for p: Person;
    when in_researcher_registry(p);
    then may_enter_reading_room(p);
}

@source(ARCHIVE_RULES_P4)
rule RareRoomAccess strict {
    for p: Person;
    when in_researcher_registry(p) and accredited(p);
    then may_enter_rare_room(p);
}
```

## Check

| Facts | Question | Answer |
|---|---|---|
| registry | general room | `TRUE_ONLY` |
| registry | rare-collections room | `NEITHER` |
| registry, without the `GeneralReadingRoom` norm | general room | `NEITHER` |

The third row is a counterfactual: with the norm cut out of the
page the question is asked again. That verifies the answer comes from
exactly the added norm, not from something the package held before.

What the exercise teaches. An anchor by fragment identifier, not by
string: with it the compiler knows which text the norm rests on, and
a text substitution breaks the build with the `LDC-E5201` code. The
string key from the first-package page gives no such check.