<feed xmlns='http://www.w3.org/2005/Atom'>
<title>colitur.git/test/test_ics.ml, branch v0.9.0</title>
<subtitle>deterministic OCaml engine to compute and validate liturgical calendars for multiple rites, template-driven output to year 9999</subtitle>
<id>https://git.labunix.xyz/colitur.git/atom?h=v0.9.0</id>
<link rel='self' href='https://git.labunix.xyz/colitur.git/atom?h=v0.9.0'/>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/'/>
<updated>2026-08-19T07:26:17Z</updated>
<entry>
<title>fix(render): omit DTEND at the domain's own last day, 9999-12-31</title>
<updated>2026-08-19T07:26:17Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-19T07:26:17Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=d71504ad9fc39b735689da32fa0be8a63c2cc7f8'/>
<id>urn:sha1:d71504ad9fc39b735689da32fa0be8a63c2cc7f8</id>
<content type='text'>
F1: Date.add_days is UNBOUNDED (date.mli) -- only Date.make enforces
1583..9999 -- and Date.to_iso8601 pads but never truncates, so
9999-12-31's naive successor formatted as "10000-01-01", and compact
turned that into a 9-digit, non-conformant DATE on the last VEVENT of
year 9999. Confirmed at the source before fixing, and reproduced
against real `colitur emit --format ics --from 9999 --to 9999` output
(DTEND;VALUE=DATE:100000101) before touching any code.

RFC 5545 section 3.6.1: a VEVENT with a DATE-valued DTSTART and
neither DTEND nor DURATION has an implicit one-day duration, so
omitting DTEND for that one event is the standard's own correct
answer, not a workaround. dtend_of re-derives the successor's
year/month/day and re-validates them through Date.make -- the one
function that actually enforces the domain -- before trusting the
string; None means the caller omits the DTEND line entirely.

F2 (minor, same function): documented next_day's own Error branch as
dead-but-silent on shipped data (event's iso &lt;&gt; "" guard is the only
caller and always parses) -- behaviour unchanged, comment only.

Two new tests: the domain's last VEVENT (DTSTART 99991231) has no
DTEND line at all; every DTEND anywhere in a 9999 feed is exactly 8
digits (the general form of the bug, catches a regression anywhere
else in the domain too). Existing 2027/2028 DTEND-arithmetic
assertions untouched and still pass.

Mutation-proved: both new tests fail against the pre-fix code
(9-digit DTEND value caught verbatim), pass after.
</content>
</entry>
<entry>
<title>feat(render): iCalendar emitter, RFC 5545</title>
<updated>2026-08-19T07:09:36Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-19T07:09:36Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=6abc243e5d40bd60174a3fb1affc9517b0ac5617'/>
<id>urn:sha1:6abc243e5d40bd60174a3fb1affc9517b0ac5617</id>
<content type='text'>
Not a template job: folding, escaping, exclusive DTEND and stable UIDs
are rules a logic-less template cannot enforce, and each fails silently
in a subscriber's client rather than loudly at generation.

  DTEND is EXCLUSIVE for an all-day event (section 3.6.1). Wrong here
  shows every event a day short, everywhere.
  UIDs are YYYYMMDD-&lt;rite&gt;@colitur and stable across regenerations
  (section 3.8.4.7). Wrong here duplicates the whole year in every
  subscriber's phone, months later.
  Every line is CRLF-terminated and folded at 75 octets (section 3.1).
  No RRULE: a liturgical calendar is not a recurrence rule. Asserted, so
  nobody optimises it later.

DTSTAMP is a parameter, not a clock read. RFC 5545 requires it and the
obvious implementation reads the wall clock -- which violates the
kernel's determinism rule and would make two feeds from identical data
differ byte-for-byte, defeating reproducible builds and any reviewable
diff on a published tree.

Corrected one test literal against real engine output: DTSTAMP is a
per-VEVENT property (section 3.8.7.2), not calendar-level, so the
default-value line count is 365 (every event), not 1.

Mutation-tested: a non-exclusive DTEND reddens the suite.
</content>
</entry>
</feed>
