# Recurring duty ## Intention I want to create a separate duty for each occurrence of a finite schedule. A three-day schedule yields three instances. ## Incorrect form and why it stays silent ```text title="Incorrect form" recurring every 1 calendar_day over [@2026-09-01, infinity) { ... } ``` The schedule must be finite; an open upper bound does not mean “show only the known part”. The lowering of a correct finite example is fixed; see the boundary. ## Correct form ```law language "law.core" version "0.2"; package recipes.a.r09 version "0.1.0"; namespace "urn:recipe:a-positions:09"; entity Person; relation registered(p: Person); relation done(p: Person); relation filed(p: Person, period: Integer); rule R strict { for p: Person; when registered(p); then duty Report { bearer p; goal recurring every 1 calendar_day over [@2026-09-01, @2026-09-04) { achievement { condition filed(p, occurrence.index); window [occurrence.start, occurrence.end); } } }; } ``` ## Frozen execution scene **The normative expectations below are executed by both implementations.** Lowering yields occurrence meta-terms — field terms over the occurrence reference; the previous const-ref rejection is closed, and the scenes below show the corrected outcome. The absence of arbitrary rejections is checked separately. | Facts and snapshot | Question | Answer | |---|---|---| | first occurrence; 2026-09-01 | `positions()` | `position_count(Report, ACTIVE, 1); expect position_count(Report, PENDING, 2);` / `COMPUTED` | | after the schedule; 2026-09-05 | `positions()` | `position_count(Report, UNDETERMINED, 3);` / `COMPUTED` | | one performed occurrence; 2026-09-05 | `positions()` | `position_count(Report, SATISFIED, 1); expect position_count(Report, UNDETERMINED, 2);` / `COMPUTED` | ```law test "first occurrence active with later pending" { given { context { legal_time @2026-09-01; decision_time @2026-09-01T09:00:00+05:00; knowledge_time @2026-09-30T09:00:00+05:00; timezone "Asia/Almaty"; } assert registered(entity_ref("urn:recipe:a-positions:09:p")); } evaluate positions(); expect position_count(Report, ACTIVE, 1); expect position_count(Report, PENDING, 2); expect evaluation_status == COMPUTED; } ``` ```law test "undetermined after schedule without data" { given { context { legal_time @2026-09-05; decision_time @2026-09-05T09:00:00+05:00; knowledge_time @2026-09-30T09:00:00+05:00; timezone "Asia/Almaty"; } assert registered(entity_ref("urn:recipe:a-positions:09:p")); } evaluate positions(); expect position_count(Report, UNDETERMINED, 3); expect evaluation_status == COMPUTED; } ``` ```law test "performed occurrence satisfied with rest undetermined" { given { context { legal_time @2026-09-05; decision_time @2026-09-05T09:00:00+05:00; knowledge_time @2026-09-30T09:00:00+05:00; timezone "Asia/Almaty"; } assert registered(entity_ref("urn:recipe:a-positions:09:p")); assert filed(entity_ref("urn:recipe:a-positions:09:p"), 0); } evaluate positions(); expect position_count(Report, SATISFIED, 1); expect position_count(Report, UNDETERMINED, 2); expect evaluation_status == COMPUTED; } ``` ```python >>> import runpy >>> check = runpy.run_path("docs/recipes/a-positions/resources/check.py") >>> check["check_boundary"](https://github.com/arxohq/law/blob/master/docs/recipes/a-positions/9) 'А9: граница проверена' ``` ## Counterfactual Mutation: `over [@2026-09-01, @2026-09-04)` → `over [@2026-09-01, infinity)`; rejection LDC-E1346. Additional counterfactuals are shown as separate scenes. ## Boundary The index starts at zero and is part of the position identity. A monthly step needs month_end; calendar_day here does not need that policy. Lowering of occurrence.start/index/end yields field terms over the occurrence reference; the previous const-ref rejection is closed, see the scenes above.