# nb-11 — Appeal: reading, judgment and precedent *Northbridge is fictional. Every applicant, hearing officer, precedent and court cited here is synthetic and unofficial. Northbridge is a training story, not a real deployment, and nothing here is legal-validity advice. Verified profile: `law 0.1.0`, `law.core/0.2`.* ## Situation Ann owns a second car and asks the permit office for a second parking permit. The clerk refuses: under the office's working reading, one household gets one permit, so `second_permit(ann)` is false. Ann appeals. At the hearing, three questions land on the table. First, which reading governs — the clerk's narrow one, or Ann's broad one under which an otherwise eligible resident gets the second permit? Second, Ann pleads hardship — a question nobody at the desk can answer; only the hearing officer's judgment settles it. Third, fellow appellant Bob lives in the city but keeps a second home outside it, and an old HIGH court decision on exactly that pattern is put on the table. Eligibility rules ([nb-01: First permit: facts, a rule and a question](/tutorials/northbridge/nb-01-first-permit/) through [nb-03: Exceptions and conflicting rules](/tutorials/northbridge/nb-03-exceptions/)) answered "does the rule fire?". Duties ([nb-09: From permit to duties and powers](/tutorials/northbridge/nb-09-duties-powers/)) answered "who owes what once it fires?". This article answers what happens when the answer is contested. The three hearing questions map to five constructs. Rival readings are named as **interpretations** — one reading per container — and the closed list of rivals plus how one is chosen is an **interpretation group**. The hardship question marks the point where only a human decision can move the case: a **judgment** is a fact that only an authority's decision can supply. The old HIGH court decision is reused without copying through its **factors** — the fact pattern it turned on — and the **precedent** itself, which the engine carries to new facts. Each construct is explained again where it first appears below. ## Prerequisites You need [nb-01: First permit: facts, a rule and a question](/tutorials/northbridge/nb-01-first-permit/) for facts, strict rules, `truth(...)` queries and `law test` as the way to check a claim; [nb-02: Why a missing fact is not a refusal](/tutorials/northbridge/nb-02-missing-fact/) for the four truth statuses, where `NEITHER` means "no conclusion either way" and never a refusal; and [nb-03: Exceptions and conflicting rules](/tutorials/northbridge/nb-03-exceptions/) for strict rules and how conflicting conclusions resolve. Two issue flags appear below: `INTERPRETATION_REQUIRED` (no reading chosen) and `REQUIRES_JUDGMENT` (the authority has not spoken yet). [nb-09: From permit to duties and powers](/tutorials/northbridge/nb-09-duties-powers/) showed duties and powers. Appeals resolve what is contested about relations like those: the hearing in this article is where an exercised objection — the `MayObject` power from [nb-09: From permit to duties and powers](/tutorials/northbridge/nb-09-duties-powers/) — would be heard. None of the five constructs decides a case by itself. The group selects the reading, the judgment supplies the missing fact, the precedent carries a past outcome to matching facts. Where any of the three is absent, the engine stops with a named issue instead of guessing. That stop is the limit of automatic decision, and it is the point of the design. ## Minimal example All fragments are excerpts from `packs/examples/language-demo/appeals/package.law` (identifiers as written; package header, imports, type alias and unrelated relation declarations cut). Each fragment is marked `Excerpt`. Excerpt 1 — the narrow reading (lines 21–28). An **interpretation** is a named container for rules that belong to one reading of the law. ```law interpretation Narrow { status reviewed; rule NarrowReading strict { for a: Applicant; when second_vehicle(a); then not second_permit(a); } } ``` Look at what the container holds: an ordinary strict rule. Under `Narrow`, a second vehicle alone defeats the second permit — the clerk's reading, stated with no new rule machinery. The novelty is the `interpretation` wrapper that names this reading as one rival among several. Excerpt 2 — the broad reading (lines 30–37). The rival container: eligibility carries over to the second vehicle. ```law interpretation Broad { status reviewed; rule BroadReading strict { for a: Applicant; when second_vehicle(a) and demo.northbridge.permits::permit_eligible(a); then second_permit(a); } } ``` Look at the rule's second premise: it reaches into the permits package for `permit_eligible`, the relation derived in [nb-01: First permit: facts, a rule and a question](/tutorials/northbridge/nb-01-first-permit/). Under `Broad`, the same second-vehicle fact plus eligibility yields the permit instead of refusing it. Same fact, opposite conclusion — the reading decides. Excerpt 3 — the group that chooses (lines 39–42). An **interpretation group** lists the rival readings and declares how one is picked; `exactly_one` means the context must select precisely one. ```law interpretation_group SecondVehicle { alternatives Narrow, Broad; selection exactly_one; } ``` Look at the two lines inside the group: the closed list of rivals, and `selection exactly_one`. The case context carries `interpretation Broad` (or `Narrow`); with no selection the question stays open by construction, flagged `INTERPRETATION_REQUIRED` rather than defaulted. Excerpt 4 — the judgment and the rule waiting on it (lines 44–52). A **judgment** declares a relation whose instances only an authority's decision can supply — here `hardship`, vested in the `HearingOfficer`. ```law external judgment relation hardship(a: Applicant) { authority HearingOfficer; } rule HardshipWaiver strict { for a: Applicant; when applied_for_permit(a) and hardship(a); then hardship_waiver(a); } ``` Look at the two parts together. The `external judgment` declaration vests `hardship` in the `HearingOfficer`: only that authority's decision can supply the fact. `HardshipWaiver` is otherwise an ordinary strict rule — but its `hardship(a)` premise is one no desk fact can satisfy. Only an adjudicated judgment makes the waiver true. Excerpt 5 — the fact pattern a past case turned on (lines 54–66). A **factors** block names the domain predicate both sides share (`lives_in_city`) and which side each distinguishing fact favors: `plaintiff` facts favor following, `defendant` facts favor distinguishing. ```law factors ResidencyLine { for a: Applicant; domain lives_in_city(a); plaintiff lives_in_city; defendant second_home; courts HIGH; LOW; } rule SecondHomeNotResident strict { for a: Applicant; when second_home(a); then not resident_for_permit(a); } ``` Look at the side labels. `lives_in_city` is shared ground marked `plaintiff`; `second_home` is the `defendant` fact that tells cases apart. The pattern separates what Ann's and Bob's cases have in common from the one fact that can distinguish them. The strict rule below the block is the fallback: where the precedent is distinguished away, a second home defeats residency. Excerpt 6 — the past decision itself (lines 68–73). A **precedent** pins one decided instance of a factors pattern — court, date, winning side and outcome — so the engine can carry it to new facts. ```law precedent P1 of ResidencyLine { court HIGH; decided @2020-06-01; plaintiff lives_in_city; outcome resident_for_permit(a); } ``` Look at the four pinned details: court, date, winning-side factors, and outcome. P1 says the HIGH court granted `resident_for_permit` on the city-living facts. A new case with the same factors follows it; one with an extra defendant-side factor is distinguished back to the general rule. ## Command and result Run the appeals suite: ```sh law test packs/examples/language-demo/appeals ``` Observed result (engine `law 0.1.0`) — all seven scenario lines plus the summary: ```text law test demo.northbridge.appeals: мир demo.northbridge.appeals, demo.northbridge.calculations, demo.northbridge.permits, demo.northbridge.vocabulary ok [demo.northbridge.appeals] tests/appeals.lawtest / broad reading ok [demo.northbridge.appeals] tests/appeals.lawtest / narrow reading ok [demo.northbridge.appeals] tests/appeals.lawtest / no selection — open question ok [demo.northbridge.appeals] tests/appeals.lawtest / judgment not yet rendered ok [demo.northbridge.appeals] tests/appeals.lawtest / judgment rendered ok [demo.northbridge.appeals] tests/appeals.lawtest / precedent followed ok [demo.northbridge.appeals] tests/appeals.lawtest / precedent distinguished итого: 7 проверено, 7 прошли, 0 не прошли, 0 не исполнены; код 0 ``` All seven tests pass: each answer matched its expectation. That says the machine selects, waits, follows and distinguishes as declared — it is not a ruling that Ann deserves the second permit. The first line names the world under test: the appeals package together with the calculations, permits and vocabulary packages it is evaluated with. The summary line is in Russian and says that 7 tests were checked, 7 passed, none failed and none were left unexecuted, with exit code 0. The package also passes the static check: ```sh law engine check packs/examples/language-demo/appeals/package.law ``` ```text check OK: packs/examples/language-demo/appeals/package.law ``` `check OK` means the package file is well-formed; the suite run above is what exercises its behavior. What the decisive tests assert (all in `packs/examples/language-demo/appeals/tests/appeals.lawtest`): | Test | Setup | Expects | |---|---|---| | `broad reading` | `second_vehicle` + resident + registered car, `interpretation Broad` | `truth(second_permit(ann))` TRUE_ONLY | | `narrow reading` | `second_vehicle` only, `interpretation Narrow` | `truth(second_permit(ann))` FALSE_ONLY | | `no selection — open question` | `second_vehicle`, no interpretation chosen | `issue(INTERPRETATION_REQUIRED)` | | `judgment not yet rendered` | applied for permit, no hardship on record | NEITHER + `REQUIRES_JUDGMENT` | | `judgment rendered` | applied + `hardship` with `origin adjudicated` | `truth(hardship_waiver(ann))` TRUE_ONLY | | `precedent followed` | `lives_in_city(ann)` only, `interpretation Broad` | `truth(resident_for_permit(ann))` TRUE_ONLY | | `precedent distinguished` | `lives_in_city(bob)` + `second_home(bob)` | `truth(resident_for_permit(bob))` FALSE_ONLY | Note what the `Broad` test carries that `Narrow` does not. The broad rule needs `permit_eligible`, so its test asserts resident and vehicle facts too. Selecting a reading selects what must be proven: Ann's permit under `Broad` stands or falls with her eligibility, while under `Narrow` the second vehicle alone decides. ## Why this construct The task is to decide a contested case where the rule itself is disputed, one premise needs an authority's word, and a past decision constrains the outcome — and to show, for each open point, exactly what is missing. Each of the five constructs answers a different question the hearing officer actually asks. Interpretations: what are the rival readings. The group: which one governs this case. Judgment: who alone can supply this fact. Factors: what did the past case turn on. Precedent: what was decided there. One construct per question, no overloading. A plain strict rule in the style of [nb-01: First permit: facts, a rule and a question](/tutorials/northbridge/nb-01-first-permit/) states either reading but cannot name the rivalry or demand a choice. A closure from [nb-06: When the register may stay silent](/tutorials/northbridge/nb-06-register-silence/) closes a register but cannot vest a fact in an authority. Copying P1's outcome into a new rule freezes one answer where factors keep the follow-or-distinguish logic alive. The proof is the seven tests above: both readings executed, the open question flagged, both judgment states observed, and the precedent pair — followed TRUE_ONLY, distinguished FALSE_ONLY — run by `law test`, not asserted in prose. What the tests do not prove is that Broad *should* win, that Ann's hardship is real, or that P1 was rightly decided. The tests prove the machine selects, waits, follows and distinguishes as declared; no test can prove the hearing officer chose wisely. All cases are fictional data, not legal advice. ## Changed condition Take `precedent followed` and add one fact: `second_home(bob)`. With city living only (Ann), `truth(resident_for_permit(ann))` is TRUE_ONLY — her factors match P1's, so the holding carries over. With the same city fact plus a second home (Bob), the same query is FALSE_ONLY. The extra defendant-side factor distinguishes his case back to the general `SecondHomeNotResident` rule. One condition, two outcomes — and the difference is the distinguished factor, not a different rule. The same one-change logic governs readings. `broad reading` versus `narrow reading` differ in the selected interpretation, plus the eligibility facts that Broad's premises require. Assert neither selection and the third test reports `INTERPRETATION_REQUIRED` instead of any truth value. The engine never silently defaults to a reading. ## Typical mistake A tempting assumption is that an unchosen reading defaults to something — usually to the strict-looking one: "nobody selected Broad, so Narrow applies and the permit is refused." It does not. The `no selection — open question` test asserts `second_vehicle` with no interpretation in context, and the engine answers with `issue(INTERPRETATION_REQUIRED)`, not FALSE_ONLY. `exactly_one` means the choice is mandatory input, not an optional hint with a silent fallback. The fix is to treat the selected interpretation as part of the case — like a fact. If a query returns `INTERPRETATION_REQUIRED`, add the missing selection to the context, not more rules. If it returns `REQUIRES_JUDGMENT`, the case waits on the authority, not on more desk evidence. ## Limits Automatic decision stops at named issues. `INTERPRETATION_REQUIRED` and `REQUIRES_JUDGMENT` are the engine refusing to guess: no reading chosen, no judgment on record. They mark work for a human — the hearing officer — not engine failures. A judgment fact needs its authority. The rendered test carries `hardship` with `origin adjudicated`; desk assertions cannot stand in for the vested authority's word. A judgment relation is usable only where its authority has spoken. A precedent binds only inside its factors pattern. P1 moves `resident_for_permit` for city-living facts and yields to the general rule where a defendant factor appears. Outside the `ResidencyLine` domain it says nothing at all. Readings do not mix. Exactly one alternative governs per context; Broad's eligibility premises never leak into a Narrow case. Rival readings coexist in the package but never fire together. Verified profile: engine `law 0.1.0`, semantics `law.core/0.2`. The selection discipline (`exactly_one`), the judgment gate (`REQUIRES_JUDGMENT`) and the follow-or-distinguish behavior are facts about this profile's implementation, never claims about the language in general. ## Exercise Without running the engine, predict, then check with `law test`: 1. In `broad reading`, which asserted facts satisfy Broad's two premises, and which single premise would the clerk's file (second vehicle only) fail? 2. In `no selection — open question`, why does the engine report an issue rather than FALSE_ONLY — whose reading would FALSE_ONLY even be? 3. In `judgment not yet rendered`, why is the status NEITHER rather than FALSE_ONLY — what is the case waiting for, and who supplies it? 4. In `precedent distinguished`, name the shared domain fact and the distinguishing defendant fact, and say which rule decides Bob's case once P1 is distinguished away. Write down each prediction first; run the suite; explain any miss in one sentence. Checkable solution: [full solution: predictions and checkable answers](/tutorials/northbridge/solutions/nb-11-solutions/). ## Sources - Source: `packs/examples/language-demo/appeals/package.law` (readings `Narrow` / `Broad`, group `SecondVehicle`, judgment `hardship`, rule `HardshipWaiver`, factors `ResidencyLine`, rule `SecondHomeNotResident`, precedent `P1`) - Tests: `packs/examples/language-demo/appeals/tests/appeals.lawtest` (the seven reading, judgment and precedent tests) - Suite tour: `packs/examples/language-demo/appeals/README.md` - Language reference: `docs/language/09-advanced-cheat-sheet.law.md` (interpretations and advanced constructs), `docs/language/06-testing-a-package.law.md` (the `law test` reference) - Prerequisite: [nb-09: From permit to duties and powers](/tutorials/northbridge/nb-09-duties-powers/); next: [nb-12: Allocation in rounds](/tutorials/northbridge/nb-12-allocation-rounds/) Three levels: 1. **Northbridge use** (this article): Ann's second-permit appeal under rival readings, her hardship waiver waiting on the hearing officer, and Bob's residency decided by precedent P1 — verified by the seven tests above. 2. **Domain template:** whenever a decision is contested, put each rival reading in its own interpretation, force the choice with an `exactly_one` group, vest authority-only facts in judgment relations, and carry past decisions as precedents over explicit factors — so every open point surfaces as a named issue instead of a silent default. 3. **Confirmed example elsewhere:** the permits package, where the eligibility rules that Broad builds on are exercised — verified by `law test packs/examples/language-demo/permits` (28 checked, 28 passed, 0 failed). Confirmed external formalization: the Lefkowitz advertisement-as-offer holding (US case law) — package `us.caselaw.advertisement_offers`, `corpus/laws/us/caselaw-advertisement-offers/03-lefkowitz.law:31-41`, construct `precedent ... of Factors` with court/decided/outcome/ ratio/prefer.
What the permits cross-check shows The permits suite exercises resident with a car, fines refusal by priority, and defeater without negation — including `denial wins by priority` (FALSE_ONLY where the refusal outranks eligibility). Readings select the rule; eligibility rules do the proving.
Sources and scope of verification The Lefkowitz precedent was decided `@1957-12-20`, with its ratio a subset of the plaintiff-side factors and a `prefer` over `AdvertisementIsNotAnOffer`. A past decision carried over explicit factors with a named defeated rule — the same shape as precedent P1 deciding Bob's case. Evidence: `docs/research/constructs/25-argue-precedent/corpus-forms.en.md`, section 2 (rated exemplary there). The recorded verification confirms the construct's presence at the cited lines only, by direct source read; it makes no claim about deployment, runtime behavior, or legal correctness.