Merge remote-tracking branch 'origin/loops/events' into arch-events-remerge
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 46s

This commit is contained in:
2026-07-03 22:03:48 +00:00
10 changed files with 1151 additions and 14 deletions

View File

@@ -18,7 +18,7 @@ capacity rules, transactional booking, and a flow-driven notification dispatcher
## Status (rolling)
`bash lib/events/conformance.sh`**311/311** (Phases 1-4 + 10 ext: …timezones+DST, e2e delivery pipeline, cross-event conflict-checked booking)
`bash lib/events/conformance.sh`**391/391** (Phases 1-4 + 14 ext + tz iCal export via TZID + VTIMEZONE + southern-hemisphere DST incl. iCal round-trip)
## Ground rules
@@ -88,6 +88,63 @@ lib/events/api.sx ── (events/schedule) (events/book) (events/agenda) ──
## Progress log
- 2026-06-10 — Harden southern-hemisphere DST: explicit iCal coverage for the
previous commit's unverified claim that "southern zones round-trip through
iCal unchanged". Added a Sydney VTIMEZONE export block (TZID:Australia/Sydney,
DAYLIGHT→+1100/STANDARD→+1000, first-Sunday rules BYMONTH=10/4 BYDAY=1SU, and
DAYLIGHT DTSTART:19701004T020000 — proving the 480 rule time folds back to
local 02:00 AEST) and a southern-zone DTSTART;TZID export→import round-trip.
+7 tests (ical 63). 391/391 green.
- 2026-06-10 — Southern-hemisphere DST. The `:dst` zone model assumed northern
ordering (dst-start < dst-end, DST = [start, end)); southern zones (DST begins
~Oct, ends ~Apr) have dst-start > dst-end and so silently never entered DST —
`ev-tz-offset` returned std year-round. Fixed by detecting the ordering: when
start < end DST is the interval [start, end); when start > end DST wraps the
year boundary (active when `utc ≥ start OR utc < end`). Added predefined
`ev-tz-sydney` (AEST +600 / AEDT +660; transitions 02:00 AEST first-Sun-Oct
and 03:00 AEDT first-Sun-Apr, both 16:00 UTC the prior Saturday → rule time
480). VTIMEZONE export already rule-agnostic, so southern zones round-trip
too (the 480 folds the from-offset back to the correct local 02:00/03:00).
+8 tests (timezone 25): summer/winter offsets, both transition dates,
local→utc both seasons, and a daily expansion crossing the autumn DST-end that
shifts in UTC (1320·1320·1380·1380·1380) yet stays 09:00 local. 384/384 green.
- 2026-06-07 — VTIMEZONE iCal export (supersedes the UTC-Z tz fix — full DST
fidelity). A tz event now exports DTSTART;TZID=<name>:<local> (+ EXDATE/RDATE
in the same TZID-local form; UNTIL stays UTC per RFC), and the VCALENDAR emits
a VTIMEZONE per distinct zone with DAYLIGHT/STANDARD sub-components generated
from the zone's transition rules (offsets + FREQ=YEARLY;BYMONTH;BYDAY) — the
London/Paris blocks match real-world definitions exactly. So a client recurs
the event at a fixed WALL-CLOCK time, DST-correct (the prior caveat is gone).
`ev-ical-vtimezone`, `ev-ical-offset`, distinct-zone collection; importer now
tolerates the ;TZID= parameter. +16 tests (ical 56), 376/376 green.
- 2026-06-07 — Fix: timezone-aware iCal export. Bug — tz events store wall-clock
LOCAL times, but export stamped them with a `Z` (UTC) suffix, so a London
18:00 event falsely read as 18:00 UTC. `ev-ical-conv` now converts a tz
event's DTSTART / UNTIL / EXDATE / RDATE local→UTC before formatting (London
summer 18:00 → 170000Z; Paris → 160000Z); non-tz events unchanged. Documented
caveat: a UTC RRULE drifts from a wall-clock-stable tz recurrence across a DST
boundary — full fidelity needs VTIMEZONE (deferred). +6 tests, 366/366 green.
- 2026-06-07 — iCalendar import / round-trip (extension). `ical.sx` now parses
VEVENT/VCALENDAR text back into events (`ev/ical-lines->event`,
`ev/parse-vcalendar`): DTSTART/DURATION/RRULE (incl. ordinal BYDAY, BYMONTHDAY,
UNTIL/COUNT/INTERVAL) and EXDATE/RDATE. Round-trip is occurrence-exact —
export→import expands to the identical occurrence set (tested across one-off /
daily-count / weekly+exdate+rdate / monthly-ordinal / bymonthday). Completes
bidirectional interop. +19 tests, 360/360 green.
- 2026-06-07 — Whole-series booking (extension). `ev/book-series!` /
`ev/cancel-series!` apply a booking/cancel to every occurrence of one event
in a window (e.g. RSVP the whole weekly class), returning per-occurrence
(occ-key status) results; capacity is still enforced per occurrence (some
:booked, some :full). Idempotent re-book (all :already). `ev/series-count`
(tally a status), `ev/series-booked` (which occurrences the actor holds).
+9 tests, 341/341 green. This was the last flagged feature — surface saturated.
- 2026-06-07 — iCalendar (RFC 5545) export (extension). `ical.sx` serializes
events to VEVENT / VCALENDAR text for import by standard clients. UTC
basic-format stamps (YYYYMMDDTHHMM00Z), DURATION (PT#H#M), and the full RRULE
model (FREQ/INTERVAL/COUNT/UNTIL/BYDAY incl. monthly ordinals "2TU"/"-1FR"/
BYMONTHDAY) plus EXDATE/RDATE. Line-oriented: `ev/event->ical-lines` /
`ev/events->ical-lines` return content lines; `ev/ical-render` joins with
CRLF (wire format). +21 tests, 332/332 green.
- 2026-06-07 — Cross-event conflict-checked booking (extension). Capacity is
per-event, but `ev/book-checked!` also prevents an attendee double-booking
THEMSELVES across different events: it consults the actor's persist-derived