# Duty: who, what, and by when Until now every norm derived a fact: admitted, refused, check requested. But more often law does not state but prescribes: "must return", "must keep", "must notify in time". Such a prescription has a bearer, an aim, and a window, and its answer is not "yes" or "no" but a status: not yet due, active, fulfilled, violated. This is a normative position, and `then duty` is the corpus's second most frequent head: 3,023 occurrences in 234 packages out of 508 (measured 05.09.2026). The archive issues documents for home use. A researcher must return a document by its term and keep it intact for the whole issue period. ```law language "law.core" version "0.2"; package tutorial.archive version "0.5.0"; namespace "urn:law:tutorial:archive"; entity Person; relation document_lent(p: Person, issued: Date, due: Date) kind empirical { key(p); } relation document_returned(p: Person) kind empirical; relation document_intact(p: Person) kind empirical; relation extension_granted(p: Person) kind institutional; relation non_return_recorded(p: Person, on: Date) kind empirical { key(p); } relation late_fee_due(p: Person) kind institutional; ``` ## Do by the term The return duty is an achievement aim: the condition must become established inside the window. The window here is not a literal but two dates from the issue fact — the corpus's most frequent form. Extending the issue removes the duty; the exception is written with an `unless` clause, so the rule is defeasible. ```law rule ReturnRule defeasible { for p: Person; for issued, due: Date; when document_lent(p, issued, due); then duty Return { bearer p; goal achievement { condition document_returned(p); window [issued, due]; } }; unless document_lent(p, issued, due) and extension_granted(p); } ``` `bearer` is the duty-holder, the only mandatory party field; `beneficiary` is not named here. `condition` is the fulfilment predicate, and it is absent from the rule body: the aim reads a conclusion, not a premise. Write in `condition` the same `document_lent` as in `when` and the duty will be fulfilled at the moment it arises, requiring nothing. Issue from 1 to 31 March 2026. Let us ask the position's status on different dates of law. | `legal_time` | Facts beyond issue | `Return` | |---|---|---| | 15 February | — | `PENDING` | | 15 March | — | `ACTIVE` | | 15 March | return | `SATISFIED` | | 10 April | — | `UNDETERMINED` | | 10 April | non-return recorded 5 April | `VIOLATED` | | 15 March | non-return recorded 10 March | `ACTIVE` | | 10 April | extension | `DEFEATED` | The second row in the case language looks like this (why the block does not compile together with the page — below): ```law test "срок не вышел — обязанность активна, не нарушена" { given { context { decision_time @2026-05-01T09:00:00+05:00; knowledge_time @2026-05-01T09:00:00+05:00; legal_time @2026-03-15; timezone "Asia/Almaty"; } assert document_lent(entity_ref("urn:tutorial:ivanova"), @2026-03-01, @2026-03-31) { id "assert-lent"; origin case_input; } } evaluate positions(); expect position(Return, ACTIVE); expect not position(Return, VIOLATED); expect evaluation_status == COMPUTED; } ``` The test name reads: "Term unexpired — the duty is active, not violated." The `positions()` query collects all positions of the case; the `position(Template, STATUS)` observation is targeted — it concerns one duty. The summary `normative_status` field with several norms in the case answers `UNDETERMINED`, and one position cannot be checked with it. This observation lives only in the test file: inside the page-package, `position(…)` would read as a call of an undeclared function, and `check` would refuse. So the block above is text, while the ready-made test file holding all twelve scenarios of this page is executed separately. **The fourth row is the point of the page.** The term has expired, nothing is known about return, and the answer is `UNDETERMINED`, not `VIOLATED`. A violation is not derived from silence: absence of proof of fulfilment is not proof of non-fulfilment. For `VIOLATED`, the aim condition must hold a negative support — the very kind the negation tutorial was about. Here a control act gives it: an archive officer recorded the non-return, and the norm translates the record into "not returned". ```law rule NonReturnRecorded strict { for p: Person; for on: Date; when non_return_recorded(p, on); then not document_returned(p); } ``` Legally it must be so: non-return is established by control, not by the calendar. The sixth row is the same record, but the term has not yet expired: the duty is alive, `ACTIVE`. The date of law must stand after the window. The seventh row is the extension. The defeater produced by the `unless` clause defeats the rule's application, and the position shows with the `DEFEATED` status. This is not "the duty was and ceased": the very ground on which it would have arisen is defeated. Note the defeater must bind every payload variable — here the bearer and both window bounds — which is why `unless` repeats the issue fact. A defeater binding only the bearer would defeat positions it said nothing about, and the compiler will not accept it. ## Hold the state Intactness is a maintenance aim: the condition must hold across the whole window, not become true once. ```law rule KeepIntactRule strict { for p: Person; for issued, due: Date; when document_lent(p, issued, due); then duty KeepIntact { bearer p; goal maintenance { condition document_intact(p); window [issued, due]; } }; } ``` | `legal_time` | Facts beyond issue | `KeepIntact` | |---|---|---| | 15 March | damage established | `VIOLATED` | | 15 March | — | `ACTIVE` | | 10 April | — | `UNDETERMINED` | The asymmetry is deliberate. Maintenance can be violated by one counterexample, read at once without waiting for the window's end. It cannot be fulfilled by one fact: saying `SATISFIED` needs completeness of observation over the whole window — a monitoring certificate, a closure covering the window entirely, or an authority's decision. Without them, `UNDETERMINED` remains after the window. "Nobody noticed damage" does not mean "there was no damage". ## The status vocabulary | Status | When | |---|---| | `PENDING` | the window has not started | | `ACTIVE` | the window runs, the condition is not established | | `SATISFIED` | achievement: the condition established in the window; maintenance: observation completeness confirmed | | `VIOLATED` | achievement: the window closed and non-fulfilment established; maintenance: a counterexample in the window | | `EXPIRED` | the window closed on a liberty or a ban — they are neither fulfilled nor violated | | `UNDETERMINED` | the window closed, with nothing to establish either fulfilment or violation | | `DEFEATED` | the position's ground is defeated by a defeater | | `CONFLICTED` | incompatible statuses established at one moment | Statuses are not an enum field but institutional literals with their own support: `violated(Return)` holds the same four states as any statement, and `CONFLICTED` is `BOTH` on a status. ## A consequence is a separate norm The overdue fine is not a property of the duty but another norm, on consequences. It is written from the same established facts: the non-return record is dated past the term. ```law rule LateReturnFee strict { for p: Person; for issued, due, on: Date; when document_lent(p, issued, due) and non_return_recorded(p, on) and on > due; then late_fee_due(p); } ``` | Non-return record | `late_fee_due` | |---|---| | 5 April | `TRUE_ONLY` | | 10 March | `NEITHER` | The first row is the test from this page, byte for byte; it is an ordinary `truth` query, and it compiles together with the page: ```law test "штраф: невозврат зафиксирован после срока — TRUE_ONLY" { given { context { decision_time @2026-05-01T09:00:00+05:00; knowledge_time @2026-05-01T09:00:00+05:00; legal_time @2026-04-10; timezone "Asia/Almaty"; } assert document_lent(entity_ref("urn:tutorial:ivanova"), @2026-03-01, @2026-03-31) { id "assert-lent"; origin case_input; } assert non_return_recorded(entity_ref("urn:tutorial:ivanova"), @2026-04-05) { id "assert-non-return"; origin case_input; } } evaluate truth(late_fee_due(entity_ref("urn:tutorial:ivanova"))); expect truth_status == TRUE_ONLY; } ``` So violation, liability, and sanction stay different layers: a `VIOLATED` on the position says the duty was not fulfilled; the fine says what is due for it; and whether there are grounds to release from the fine is a third norm, cancelling neither the first nor the second. ## A window is not a norm's validity term A duty holds two different times, and confusing them is the costliest mistake on this layer. The rule's `effective` (the time tutorial) says from which date the norm exists; the aim's `window` says by when to fulfil. Outside `effective` there is no position at all; outside `window` there is one — `PENDING` before and `UNDETERMINED` or `EXPIRED` after. "The norm does not yet exist" and "the term has not started" are different answers, and both are needed. Hence the rule: the "from 1 January 2027" milestone goes into the rule's `effective`, while the aim window counts from the event — issue, notice, entry into force for this person. A duty's window must not be taken from an edition's validity term: the term to return a document does not match the archive rules' validity term. ## Compiler refusals There are two mandatory fields, with a refusal for each missing: ```text error LDC-E1305: duty "Return" без bearer (§123) error LDC-E1305: goal нормы "KeepIntact" без window (§124: обязателен) ``` The diagnostics read: 'duty "Return" without `bearer`' and 'the "KeepIntact" norm's `goal` without `window`'. A window boundary is a value: a date, a rule variable, or `infinity`. A bare name found among neither binders nor constants is rejected by the compiler: ```text error LDC-E2115: имя "moment" в границе интервала §20 не объявлено: оно не связано ни `for` правила, ни `let`, и не объявлено ни `const` §54 … ``` The diagnostic reads: 'name "moment" in an interval boundary is not declared: it is bound by neither the rule's `for` nor `let`, and declared by no `const` …'. A position's exception lives only in a defeasible rule. Make `ReturnRule` strict, keeping `unless` — a refusal: ```text error LDC-E4110: ReturnRule: `unless` на strict-правиле (§149) — сделайте правило defeasible либо внесите условие применимости в strict-тело ``` The diagnostic reads: "'ReturnRule': `unless` on a strict rule — make the rule defeasible or move the applicability condition into the strict body". A position has no contrary form: `unless … then not Return` is a refusal, because a "non-duty" means nothing. Opposing positions goes by the conflict patterns, not by negation: ```text error LDC-E1302: rule "ReturnRule": контрарная форма `unless … then …` при норм-голове не определена (§107.1): комплемента у позиции нет ``` The diagnostic reads: 'rule "ReturnRule": the `unless … then …` contrary form on a norm head is undefined: a position has no complement'. And that very defeater that bound only the bearer. Replace `unless` with a bare `extension_granted(p)`: ```text error LDC-E4101: ReturnRule/unless/0: норм-голова "Return" (поля: goal.window) использует несвязанные переменные [issued, due] ``` The diagnostic reads: 'ReturnRule/unless/0: the "Return" norm head (fields: goal.window) uses unbound variables [issued, due]'. All six refusals belong to the language. One lesson cannot be pinned the same way: a second `goal` clause in one duty silently replaces the first, `check` is clean, the CLIR keeps the last. Two aims are two rules. ## Next Duty is one of four modalities. Ban, liberty, power, and immunity are the track's next page; there it will turn out that a ban in the core is not violated by itself, and violation is expressed by a paired duty. And how to count an aim window not from a fact's date but "within ten business days" is told by the tutorial on terms. The exercise for this page is [/tutorials/exercise-duty/](/tutorials/exercise-duty/).