# 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.