Skip to content
docs
Arxo ↗

Periods and calendar: deadline policy, add_calendar_period, add_business_days

For LLMs7 sections

In one sentence: these constructs answer the question “when a deadline falls”. Take them when a norm names a period (“within a month”, “ten business days”): the period policy says how to count, and the term counts; the calendar snapshot is attached only when the period runs in business days.

Deadlines are calendar steps and business-day counts under a named period policy: a business-day count always pins the official calendar snapshot, a calendar step never does.

Instead ofSelection rule
add_calendar_period vs add_business_daysPeriod in calendar units (month, year, week, day-step) — add_calendar_period, no calendar snapshot is ever taken. Period in business days — add_business_days, the snapshot is always required, even with no_roll and even for calendar_day. The difference is in the term name; the calendar_day unit is allowed in both
Step vs measurement“Deadline N ahead of a date” — a step (add_calendar_period / add_business_days). “How many days between dates” (penalty per day) — the days_between measurement: asks for no snapshot, counts no business days. Seven days as an interval is days_between, not a step (EU Regulation 261/2004, see corpus-forms.md)
start_count same_day vs next_dayText counts the trigger day (“from the day”) — same_day; text counts from the next day — next_day. Price of the mistake — exactly one day: 15.01 + 1 month gives 15.02 under same_day and 16.02 under next_day (checked against both policies in the second example package)
month_end last_day_of_month vs absentA month/year step across a nonexistent date (31.01 + 1 month) — the policy is mandatory: last_day_of_month gives 28.02, absence — MISSING_POLICY, not a silent choice. The field is read only by the month/year unit
Calendar snapshot vs case factThe jurisdiction’s business calendar is pinned (a pinned dataset + law.lock line) — snapshot. Not pinned (an annual ministers’ decision that does not exist) — the business-day count comes as a case fact, and comparison against the limit is a literal in the rule (halal certification, see corpus-forms.md): honest “we do not count”, not an invented “weekends-only” calendar

Grammar: the deadline window as an interval (EBNF verbatim from the grammar)

Section titled “Grammar: the deadline window as an interval (EBNF verbatim from the grammar)”
Show syntax reference

A deadline window is an interval with value endpoints; a term boundary requires a named deadline policy, otherwise MISSING_POLICY. Goal-window syntax lives on the duty pages; only period computation lives here:

Grammar
interval_expression = expression ;
interval_literal = interval_left, interval_endpoint, ",",
interval_endpoint, interval_right ;
interval_left = "[" | "(" ;
interval_right = "]" | ")" ;
interval_endpoint = expression | "infinity" | "-infinity" ;

Package research.deadline.monthly: a report filed on day filed, deadline — one month by calendar step, same_day policy without roll.

Arxo Law
deadline policy CASE_POLICY {
start_count same_day;
include_end true;
roll no_roll;
month_end last_day_of_month;
}
rule MonthlyDue(r: Report, filed: Date) strict {
label ru-KZ official "Срок — месяц со дня подачи";
when filed_on(r, filed);
then due_on(r, add_calendar_period(filed, 1 calendar_month));
}

Case 1: filed_on(r1, @2026-01-15), context with deadline_policy CASE_POLICY. Query: evaluate truth(due_on(r1, @2026-02-15)). Case 2: filed_on(r2, @2026-01-31); query due_on(r2, @2026-02-28).

Observed engine answer (installed law, semantics law.core/0.2):

Output
law test research.deadline.monthly: мир research.deadline.monthly
ok [research.deadline.monthly#authored] tests/01-due.lawtest / urn:query:research-deadline-01
ok [research.deadline.monthly#authored] tests/02-month-end.lawtest / urn:query:research-deadline-02
итого: 2 проверено, 2 прошли, 0 не прошли, 0 не исполнены; код 0

law engine check — check OK, no warnings. The calendar step takes no snapshot: the policy is read from the case environment (calendar and policy come via the environment, not as an argument; the term arity is 2). Sensitivity: removing filed_on gives NEITHER instead of TRUE_ONLY; 31 January gives 28 February only with month_end last_day_of_month — without it the refusal is MISSING_POLICY (the two scenario tests).

Nearest wrong outcome (caught in trials): the same norm with start_count next_day answers 16.02 instead of 15.02 — a one-day mistake with no diagnostics, because both dates “look right”. The second package is devoted to it.

Second package research.deadline.start — same rule, two policies:

PolicyFilingQuestionAnswer
same_day@2026-01-15due_on(@2026-02-15)TRUE_ONLY
next_day@2026-01-15due_on(@2026-02-16)TRUE_ONLY
  • Law: French Civil Code (package fr.code_civil, France) — five-year limitation by step (then echeance_prescription_le(c, add_calendar_period(depart, 5 calendar_year)), see corpus-forms.md); the policy is a line in the case context (deadline_policy OECD_CODE_CIVIL_PRESCRIPTION).
  • Standard/protocol: EU Regulation 261/2004 (package eu.transport.air_passenger_rights, European Union) — the seven-day period is computed with days_between, not a step: no pinned source holds a calendar of non-business days for 27 member states, and opening an empty one would assert extras.
  • Religion/custom: Indonesian halal certification (package id.halal, Indonesia) — business-day periods are NOT computed: the SKB calendar is not pinned, the count comes as a case fact.
  • Science/teaching case: research.deadline.start — the start_count price of one day in miniature; the Turkish Constitution (package tr.constitution, Türkiye) — a moratorium year by step, not recomputed in days: a year is not measured in days without a leap-year decision.

Table — observed runs of this directory’s examples (installed law, semantics law.core/0.2):

FactsQuestionAnswerWhy
filing 15.01, same_day policydue_on(15.02)TRUE_ONLYstep to the corresponding date
filing 31.01, month_end last_daydue_on(28.02)TRUE_ONLYnonexistent date — last day of the month
filing 15.01, next_day policydue_on(16.02)TRUE_ONLYcount from the next day
no filing factdue_on(…)NEITHERrule did not fire
corpus term-window [appointed, add_calendar_period(appointed, 60 calendar_day)]period by stepTRUE_ONLY with a policy, else MISSING_POLICYa term boundary requires a named deadline policy (goal windows from the positions pages: 563 variable boundaries versus 3,929 literals)
  • The policy is a named package node (deadline policy Name { … }), lowering — a deadline_policy node with contentHash; the context carries only the reference; ambient policies and inline copies do not exist.
  • Without a policy (set by neither case nor profile) — MISSING_POLICY: for a conclusion question this is a refusal status with missing_inputs and the rule address, not just an issue.
  • The calendar step reads start_count from the policy, and the month/year unit additionally reads month_end; roll must be no_roll, include_end — true, otherwise MISSING_POLICY, not interpretation.
  • “Period — a month, and a non-business day rolls to the next business one” is a composition: the add_calendar_period result feeds add_business_days with zero business days; the calendar is then pinned explicitly.
  • Calendar questions do not read context axes: they take the date from the question itself.
  • Month/year boundaries are the terms month_start_of/month_end_of, year_start_of/year_end_of: neither calendar nor policy is read; weekday — weekday_of.
  1. Wrong start_count — a one-day mistake with no diagnostics (caught by trials; pitfalls.md, item 1).
  2. No month_end on a month step — MISSING_POLICY, not “last day” (pitfalls.md, item 2).
  3. business_day on add_calendar_period (and vice versa) — TYPE_ERROR: units do not mix (pitfalls.md, item 3).
  4. add_business_days without a snapshot — refusal: the snapshot is always required, even with no_roll (pitfalls.md, item 4).
  5. A “weekends-only” snapshot instead of a real calendar — an answer to the dangerous side (earlier than real); honestly — a case fact (halal; pitfalls.md, item 5).
  6. Policy as a third term argument — no: arity 2, environment (LDC-E2116; pitfalls.md, item 6).
  7. cutoff outside the HH:MM:SS canon — DEADLINE_POLICY_INVALID without normalization (pitfalls.md, item 7).
  • The official calendar is external context: it is read as data and pinned by digest, never computed.
  • Neighbouring pages: time (law date and effective), duty (goal windows), lifecycle statuses (duty deadlines).

Documentation for Arxo. Writings — blog.arxo.io.

Anonymous visit counts on stats.arxo.io, no cookies.