Skip to content

Implement If-Schedule-Tag-Match support (RFC 6638) #660

@tobixen

Description

@tobixen

⚠️ This comment is AI-generated (Claude Sonnet 4.6 via Claude Code) on behalf of tobixen

The infrastructure for Schedule-Tag is half-built: the tag is received and cached, but
If-Schedule-Tag-Match is never sent on PUT requests, leaving attendee PARTSTAT updates
unprotected against racing organizer updates.

Full analysis and suggested implementation steps are in
docs/design/TODO_SCHEDULE_TAG.md.

Summary of work needed

  1. _put / _async_put: Accept an extra_headers dict so conditional headers can
    be injected.

  2. save(if_schedule_tag_match=True): Currently accepted but silently ignored.
    Wire it through to _put by reading self.props[cdav.ScheduleTag.tag], loading first
    if the tag is not yet cached.

  3. _reply_to_invite_request: Already fetches the schedule-tag property but never
    uses it. Should call save(if_schedule_tag_match=True). The current fallback/recursive
    logic also needs cleaning up.

  4. Public schedule_tag property on CalendarObjectResource to avoid callers
    importing cdav.

  5. ScheduleTagMismatchError (subclass of PutError) for 412 responses so callers
    can handle the re-fetch-and-merge case explicitly.

  6. scheduling.schedule-tag compatibility hint — schedule-tag is a SHOULD in the
    RFC, not all servers implement it.

Background

Schedule-Tag solves the attendee-update race condition: without If-Schedule-Tag-Match,
an attendee updating their PARTSTAT can silently overwrite an organizer update that
arrived between the attendee's GET and PUT. The tag is stable across PARTSTAT-only writes,
so it uniquely identifies the scheduling-significant version of the resource.

RFC refs: https://datatracker.ietf.org/doc/html/rfc6638#section-3.2 and section 3.3.

⚠️ This comment is AI-generated (Claude Sonnet 4.6 via Claude Code) on behalf of tobixen

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions