docs← Back to article

Markdown for LLMs

Exercise 15. A complaint term in business days

The source Markdown for this article. Copy it into your assistant or download it as a text file.

Download this articlePlain text ↗
# Exercise 15. A complaint term in business days

An exercise for the [terms](/tutorials/deadlines/) page. The archive
answers a request within ten business days. The rules allow fifteen for
a complaint, counted under the same policy: from the next day, including
the last, rolling to a business day.

**Setup.** Write the complaint-reply term norm and find the date for
a complaint received Friday 6 March 2026 under Kazakhstan's official
calendar. Verify with a date a day earlier that the term is exactly that
day.

**Hint.** The answer cannot be reached by counting days on a wall
calendar: March holds holidays, and they shift. Let the engine name the
date, and explain where it came from.

Below is the solution. Try it yourself first.

## Solution

The calendar and policy from the page, plus two relations:

```law
language "law.core" version "0.2";
package tutorial.archive version "0.6.1";
namespace "urn:law:tutorial:archive";

entity Person;

source KZ_OFFICIAL_CALENDAR_2026 {
    kind law;
    jurisdiction KZ;
    number "calendar-2026";
}

calendar archive_calendar_2026 {
    timezone "Asia/Almaty";
    timezone_db "iana-tzdb@2026a";
    period [@2026-01-01, @2027-01-01);
    source KZ_OFFICIAL_CALENDAR_2026;
    resource "artifact:corpus/clir/kz-official-2026.calendar.json";
    format "law.calendar/0.1";
    content_hash "sha256:a17b851ac08e622c05c116637ecf8d818bc7b480568f5560407d69461c4b8c21";
}

deadline policy ARCHIVE_BUSINESS_DAYS {
    start_count next_day;
    include_end true;
    roll next_working_day;
}

relation complaint_received(p: Person, on: Date) kind empirical { key(p); }
relation complaint_reply_due(p: Person, due: Date) kind institutional;

rule ComplaintReplyDeadline strict {
    for p: Person;
    for on: Date;
    when complaint_received(p, on);
    then complaint_reply_due(p, add_business_days(on, 15 business_day));
}
```

The test with the engine-named date:

```law
test "жалоба получена в пятницу 6 марта — ответ до 3 апреля" {
    given {
        context {
            deadline_policy ARCHIVE_BUSINESS_DAYS;
            decision_time @2026-04-15T09:00:00+05:00;
            knowledge_time @2026-04-15T09:00:00+05:00;
            legal_time @2026-03-06;
            timezone "Asia/Almaty";
            calendar archive_calendar_2026;
        }
        assert complaint_received(entity_ref("urn:tutorial:ivanova"), @2026-03-06) {
            id "assert-complaint";
            origin case_input;
        }
    }
    evaluate truth(complaint_reply_due(entity_ref("urn:tutorial:ivanova"), @2026-04-03));
    expect truth_status == TRUE_ONLY;
    expect evaluation_status == COMPUTED;
}
```

The test name reads: "Complaint received Friday 6 March — reply due by 3 April."

Where 3 April comes from. Counting starts the next day, 7 March, and by
the 2026 calendar March holds more days off than usual: 8 March shifted
to Monday the 9th, 15 March shifted to the 16th, Nauryz 21–23 March
shifted to the 24th and 25th, plus weekends. Business days run so: 10–13
March are four, 17–20 eight, 26–27 ten, 30 March – 3 April fifteen. The
fifteenth business day is Friday 3 April, with nothing to shift. The
page's request answer, ten days from the same date, ended 27 March by the
same chain.

## Check

Both tests are in `tests/45-exercise-deadlines.lawtest`: the solution's
date and a date a day earlier expecting `NEITHER`. The policy is declared
both in the program and in the test file: without the second declaration
the runner refuses `LDC-E1333`, without the first —
`EVALUATION_REQUEST_INVALID` at runtime.

What the exercise teaches. A business-day term is a function of three
things: date, policy, and calendar. The norm implies none of them: the
policy is named in the case context, the calendar pinned by hash, and the
same test on another calendar yields another date, and without
a calendar none at all.