fix(caldav): patch the master component, and surface RECURRENCE-ID verbatim #17
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix-master-component"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Refs #16. A live defect found while assessing the recurrence proposal, plus the instance metadata that everything else in that sequence depends on.
The defect
patch_icsandparse_ical_eventboth anchored on the firstBEGIN:VEVENT. A calendar object for a recurring series holds the master and oneVEVENTper override, and RFC 5545 does not require the master first.Measured before it was fixed, with a scratch test against an override-first object:
So
update_eventon such a series renamed one occurrence, reported success, and returnedrecurrence_rule: nullfor a series that has one. A client reading that answer stops treating the event as recurring.master_event_startnow selects the component with noRECURRENCE-ID, and it is the single place that decides, so every existing call site throughevent_linesandreplace_event_propertyis fixed at once rather than one at a time.RECURRENCE-IDwas unusable for the thing it is needed forIt was parsed for
TZIDandVALUEonly and rendered to a UTC instant. AnEXDATEhas to carry the same value type andTZIDtheRRULEgenerates, so an exclusion built from ourrecurrence_idwould be exactly the silently-ignoredEXDATEthe proposal in #16 warns about — we would have produced the bug the specification is written to avoid.Eventnow carries, alongside the rendered form:recurrence_id_value— the value as the server wrote it,20260901T090000or20260901recurrence_id_tzid— absent for UTC and floating valuesrecurrence_id_range— normallyTHISANDFUTURERANGEwas dropped entirely before this. An override carrying it applies to that occurrence and every later one, and a caller that cannot see it treats a this-and-future override as a single-instance one. That is the silent-ignore #16 lists as a correctness rule, and it was live on the read path rather than hypothetical.Verified by mutation
Four, each against the full suite of 107.
master_event_startreturns the firstVEVENTpatch_edits_the_master_when_an_override_is_written_first, aloneparse_ical_eventtakes the first componenta_calendar_object_is_described_by_its_master_component, alonerecurrence_id_rangehardcoded toNonerecurrence_id_is_surfaced_verbatim_with_its_parameters, alonerecurrence_id_valuerendered instead of verbatiman_override_without_range_reports_noneThe first three kill exactly one test each, so each is load-bearing rather than covered by a neighbour. The fourth kills two because the all-day case renders differently from its verbatim value, which is the same claim from a second angle.
Gates
cargo fmt --check,cargo clippy -D warnings,cargo test --all-features(107 + 9), all green onrustc 1.98.0, run through the shared build slot.Not in this change
delete_occurrence,update_occurrence,get_event_raw, and rejectingRANGE=THISANDFUTUREon the write paths — there is no write path that can accept it yet. Sequenced on #16.