Skip to content

fix: correcting compatibility claims, sharpening inline doc - #710

Merged
tobixen merged 18 commits into
masterfrom
compatibility
Sep 16, 2026
Merged

tobixen merged 18 commits into
masterfrom
compatibility

Conversation

@tobixen

@tobixen tobixen commented Sep 10, 2026

Copy link
Copy Markdown
Member

See the commit message for details. ("Best practice" to route things through a pull request, I suppose).

Comment thread tests/test_async_integration.py Fixed
Comment thread tests/test_compatibility_hints.py Dismissed
Comment thread tests/test_compatibility_hints.py Dismissed
tobixen and others added 18 commits September 16, 2026 06:58
I'm currently working on a releas of the caldav-server-tester project,
and I've found some bugs and mistakes, behaviour has been altered a bit
in that project.  This again caused the compatibility test to break for
multiple servers.  It also caused me to flip back on some
`fragile`-observations.

Some servers do updates asyncronously.  A PUT/DELETE/MKCALENDAR etc is
sent to the calendar server, and we get "2xx OK" in return - but the
change has been queued up rather than processed.  Sometimes it's
processed within a fraction of a second, sometimes it can take minutes.
More often than not this doesn't matter at all in real life scenarioes -
but it does matter a lot for the caldav-server-tester as well as for
test code in this project!  It's possible to configure delays, but it's
not possible to probe directly what the delay should be set to.  We
already did some polling for delays on calendar creation and calendar
deletion, now it's also doing polling for delays on event creation.
Earlier `fragile` was used to mark delays in calendar creation and
deletion - now `quirk` is used.  One thing here, it's not possible to
probe the difference between a very fast asynchronous server and a
server that returns "200 OK" only after all databases are in sync.  None
of the docker-based test servers showed up as asynchronous in the first
few test rounds.  I flipped them from `quirk` to `full` _as for now_.
Cyrus later had to be flipped back to `quirk`.

Sometimes a server returns a 4xx or a 5xx error due to a feature not
supported.  This may arguably be better than silently dropping data -
but still, the support level is to be considered "ungraceful".  This was
not quite consistently probed in the caldav-server-tester.  It's now
more consistently returning "ungraceful" on such return values, and the
feature support matrix needed some upgrades.

There are some definitions of the various support levels in comments in
the compatibility_hints.py - those should eventually be moved out to
proper documentation - but as for now I've gone through and improved the
existing documentation.

Many of the changes have been done manually, but I've also had Claude
doing things for me, so ref the AI guidelines the prompts should be
included:

Prompt: (hand-edited changes in the file)
Followup-Prompt: (comment from the review process, pasted test output abridged) Test results are in.  The posteo stable-url thing [pre-existing 'unsupported' in the configuration, apparently put there by me without AI-assistance and without any documentation] seems to be hallucinated.
Prompt: (in the caldav-server-tester project) It's not possible to separate async-but-very-fast from synchronous - it could be that things will break later, but still - please move support level to "full" for cyrus, nextcloud and zimbra - and then I can move it back to "quirk" first time we observe async behaviour.
Followup-Prompt: (comment from the review process) Is this right?  In the async quirk case, the calendar only needs to be deleted once.  Now, with the async case, maybe a client that immediately would look for the calendar will see that the delete-operation failed ... but this is a corner case that probably only exists in the caldav-feature-checker!  Yank out this commit? [about a commit that made 'quirk' enter Calendar.delete()'s retry loop; it was yanked]
Followup-Prompt: (test output pasted, abridged) This is interesting: (server-tester run against Cyrus: testCheckCompatibility failed, and the write-delay probe reported behaviour 'delete-calendar takes ~1s')
Followup-Prompt: [it should be] `quirk`, not `fragile`.  The delete always goes through, it's just delayed, while `fragile` could cause the delete-operation to be retried
Prompt: (None - changes hand-edited by tobixen)
Followup-Prompt: (comment from the review process) I've tried to rewrite [the inline documentation in the comments about support levels] myself, do a quick QA on it and fix up the commit with my changes
Followup-Prompt: (While going through AI-generated code review comments, user agreed to let Claude Opus include a definition for "unknown" to the list)
Prompt: (test output pasted, abridged) And OX also is unhappy: (server-tester run, reproduced from both clones: save-load.event.recurrences.exception.reschedule expected 'unsupported', observed 'ungraceful' with "PutError at '409 Conflict'")
Prompt: Now there are four commits touching one file and some docstrings in test code - it would make sense to squash it into one, wouldn't it?

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reviewed-by: Tobias Brox <tobias@redpill-linpro.com>
2d4d360 regraded it to 'quirk' on the tester's verdict, which made
is_supported() true and so switched off Calendar.delete()'s
retry-and-poll loop - the loop is keyed on 'fragile' alone.  Cyrus
needs it: a calendar re-created on a just-deleted cal_id answers 500 to
DELETE for about a second (17 of 20 attempts on the docker server, each
accepted a second later), while a fresh cal_id deletes cleanly.  The
cause is filed upstream as
cyrusimap/cyrus-imapd#6383: the DELETED.*
mailbox name carries a whole-second timestamp, so two deletes of one
name inside the same second collide.  testCreateDeleteCalendar and
test_principal_make_calendar hit it because they tear a calendar down
and make it again.

Prompt: (test output pasted, abridged) $ pytest --last-failed (TestForServerCyrus::testCreateDeleteCalendar and TestAsyncForCyrus::test_principal_make_calendar both DeleteError at '500 Internal Server Error'; )
Followup-Prompt: It sounds like "fragile" with that behaviour note is the correct thing to have in the compatibility matrix?  Delete fails hard if the calendar was freshly created?  Or perhaps the calendar creation should be tagged as quirky and asynchronous, and all test code depending on calendars created should sleep a second?
Followup-Prompt: [do research on the cyrus issue]
Followup-Prompt: The issue should be referenced either from compatibility_hints.py, the check code or both [the Cyrus bug filed as cyrusimap/cyrus-imapd#6383 earlier in this session; done in both repos]
Followup-Prompt: [hand edit: the AI-written note condensed into human text]
Followup-Prompt: (comment from the review process) Can it be folded into 08e7496 ?
Followup-Prompt: (comment from the review process) Can this be folded into another commit?  We're on a feature branch, so force-push is allowed
Followup-Prompt: (comment from the review process) Can this be folded into the earlier cyrus issues?

AI-assisted: yes
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reviewed-by: Tobias Brox <tobias@redpill-linpro.com>
The support-level prose described "quirk" and "fragile" by how certain
the behaviour is, which left the operational difference implicit.  What
"fragile" asks for now depends on what is fragile.  A fragile write,
such as delete-calendar, may not have gone through and may be re-issued,
which is what Calendar.delete() implements.  A fragile synchronous-write
is a server that may be asynchronous but settles too fast to probe:
writes are never re-issued, and a read right after one waits or retries.
A write that always goes through but settles slowly is a "quirk".

Prompt: `fragile` means a retry is needed, `quirk` means a retry is not needed.  Keep it like that.
Followup-Prompt: (comment from the review process) For me, this is crystal clear, let me try to rephrase it:
One shouldn't retry an async operations (sic), one should wait it out.
If "synchronous-write" is declared fragile, then it's the "synchronous"-part of it that is fragile, the "write" part of it is considered to be deterministic, so no retries on the write-ops are needed.  A _read_-ops right after may need to be retried if it doesn't contain the changed/added item.  "Fragile" means it may be asynchronous under the hood, but it may not be possible to probe this (deterministically) as the write-operations settle very fast.
If calendar creation or calendar deletion is considered to be "fragile", then it's the write operation that is fragile - the creation/deletion may or may not have gone through, and if it didn't go through, then in some cases a retry may help.  If everything except calendar creation and/or calendar deletion is observed to be async, then "synchronous-write" may be considered supported, while the async nature of calendar creation/deletion is to be considered a "quirk".  For cyrus, it's well-known that the calendar delete is "fragile", it's just one oddball corner case where it may be needed to retry after 1s.
[please] make sure this is crystal clear for anyone reading the doc.
If the actual code deviates from my writing above, it needs to be fixed.

AI-assisted: yes
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reviewed-by: Tobias Brox <tobias@redpill-linpro.com>
A bare icalendar component assigned to a CalendarObjectResource gets
wrapped in a VCALENDAR, and that wrapper was built with
icalendar.Calendar.new(), which adds a random RFC 7986 UID.  Stalwart
takes the calendar-level UID to be the identity of the calendar object
resource, so a second save of the same object arrived with a new UID
and was rejected with 412 no-uid-conflict.  The wrapper is now built
explicitly, without a UID.

The async test also PUT the same event twice to one URL, first from an
icalendar.Calendar (carrying its own calendar-level UID) and then from
a bare Event - a UID change on an existing resource, which a server may
legitimately refuse.  It is now parametrized like its sync counterpart.

Prompt: It's still needed to figure out of this error (sic), it's reproducible and I've also tried to restart the epheremal stalward docker container (sic) to make sure no old state remains on the server: (pytest --last-failed --pdb output pasted, TestAsyncForStalwart::test_create_event_from_ical failing with PutError 412 no-uid-conflict)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reviewed-by: Tobias Brox <tobias@redpill-linpro.com>
Every Bedework measurement we had came from a 2018 quickstart-3.10.3
image, while upstream is alive and at 5.0.  That profile is now
`bedework_3_10_3`, a breaking rename: `features: bedework` raises a
ValueError naming both profiles.  The `bedework` test server is now a
locally built 5.0.0 image, installed from upstream's galleon feature
pack with three upstream startup bugs patched at build time; the 2018
image moved to bedework3.  The new `bedework_5_0_0` profile comes from
several caldav-server-tester runs: writes are asynchronous, a client
cannot create a collection that holds tasks (analysis upstream in
Bedework/bedework#5), text search matches
nothing, an expanded search repeats the href per instance, and a VEVENT
without SUMMARY is refused.  Task and journal storage are graded
unknown, and tests skip where no task calendar can be had.

Prompt: The bedework docker image we're using is 8 years old - but bedework seems to be a an active and alive project. (sic)
Followup-Prompt: A cheap "fix" would be to redefine "bedework" to "bedework_3_10".  Then at least the compatibility_hints is not giving misinformation.
Followup-Prompt: ok [approving the plan: version-stamp to the real 3.10.3, add a rename map rather than a bare rename, and document the provenance]
Followup-Prompt: like with ox, it seems like we need to build our own docker-image for newer versions of bedework.  Try to build a container based on the main branch.  The old bedework docker image should be remaned (sic) bedework3. [approved to go for the released 5.0.0 feature pack rather than "main branch"]
Followup-Prompt: New bedework5 container should be running and working now.  Please probe it and populate the new bedework profile in ~/caldav/compatibility_hints.py
Followup-Prompt: (comment from the review process) s/four/several/ and s/two/several/ and all is good. [on the message saying four runs and the profile comment saying two]
Followup-Prompt: `pytest --last-failed` is giving lots of bedework errors.  Please investigate.
Followup-Prompt: Either todos work or they don't.  If the server does not accept tasks, then the caldav-server-tester should report on that.  If the server does accept task (sic), the tests should pass.  If the truth is somewhere in between, we need to work out something.
Followup-Prompt: fix the profile and add the missing skips.  Make sure caldav-server-tester reports tasks as not supported for bedework.  Make sure all task-related test code skips for bedework.
Followup-Prompt: We're working on getting tests passing on bedework.
Followup-Prompt: 1) Apparently all other servers supports (sic) tasks - though many of them require tasks to be on a separate task-list.  Bedework is the only server which is declared not to support `save-load.todo`.  Tests that puts (sic) tasks on a calendar should bail out when `save-load.todo` is not supported - but apparently there are some such tests that do not bail out.  Please investigate.  Tests are slow towards bedework, but pytest keeps some database over failing tests, dosn't (sic) it?  Look into it.
Followup-Prompt: 2) comments in compatibility_hints.py writes (sic) something about a "Qproperty".  What is a Qproperty?
Followup-Prompt: 3) Actually save-load.todo should probably be unknown and not unsupported for bedework5 - it's the combo of unsupported `create-calendar.with-supported-component-types` and `save-load.todo.mixed-calendar` that should disable tests.  While being at it, look into caldav-server-tester and consider if it should report unknown rather than unsupported for save-load.todo for bedework5.
Followup-Prompt: I've modified the comments in compatibility_hints.py - all those details [that was removed] seem to belong to an issue report to the bedework project rather than in the compatibility_hints.py.  Please check if it's possible to file an issue, as well as if there already exists an issue on this
Followup-Prompt: Please follow up on issue #5 [Bedework/bedework#5] with details on the failure.
Followup-Prompt: post [the drafted comment]
Followup-Prompt: yes, fix the typo, add the link and commit.  (...)
Followup-Prompt: add the probe to the server tester.  support level "quirk" is probably OK, and a behaviour note that it's not following the RFC.
Followup-Prompt: (pytest -k bede output pasted: 2 failed, testChangeAttendeeStatusWithEmailGiven sync and async, PutError 500 missingeventproperty summary on Bedework)
Followup-Prompt: Feature + probe + test fix (Recommended) [answering: a save-load.event.no-summary feature, a tester probe, and a SUMMARY in the two test events]
Followup-Prompt: (comment from the review process) I consider "support bedework 5" as one feature.  Most of the 29 commits below is (sic) related to the task "support bedework 5".  Please squash some commits.
Followup-Prompt: Feature + separate fixes (Recommended) [answering how to squash: the Bedework commits into this one, the library fixes kept as commits of their own]

AI-assisted: Claude Opus 5 via Claude Code
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
RFC 4791 has MKCALENDAR answer 201 Created and reserves the multistatus
for reporting what could not be done, so we insisted on 201.  Bedework 5
answers 207 instead: every propstat 200 ok when the request carries
properties, and a single DAV:response holding nothing but the href when
it does not, which RFC 4918 section 13 forbids.  Either way the calendar
was created, yet make_calendar() raised MkcalendarError.  A 207 is now
accepted when nothing in it reports a failure; a multistatus with no
DAV:response at all, or with a non-2xx status, still raises.

Prompt: look into the new bedework test server.  It should be running.  It even seems impossible to createa (sic) a calendar?
Followup-Prompt: fix everything [= the MKCALENDAR failure and a container-name collision that let an older checkout destroy the Bedework 5 container; the latter went into the Bedework 5 feature commit]
Followup-Prompt: New bedework5 container should be running and working now.  Please probe it and populate the new bedework profile in compatibility_hints.py
Followup-Prompt: It should be recorded as "quirk" and 'empty-207' as behaviour.  caldav library should handle it gracefully.  Comments in compatibility_hints.py referring to the quirk as being in vaiolation (sic) of RFC 4918 §13 [answering what all_statuses_ok() should do with the status-less 207 the probe had turned up]

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reviewed-by: Tobias Brox <tobias@redpill-linpro.com>
A profile entry graded the same as an explicitly graded parent adds
nothing, since the children of such a feature resolve to its grade.
Twenty such entries across bedework_3_10_3, bedework_5_0_0, baikal,
davical, purelymail, ox and infomaniak are gone, and every feature
resolves exactly as before in every profile.  Zimbra's
delete-calendar.free-namespace stays: its comment records it on
purpose.

Prompt: Now the compatibility_hints explicitly lists `save-load.todo.*` as unsupported.  It should suffice to set `save-load.todo` to `unknown` or `unsupported`, the children will automatically inheritate (sic) the parent.  Look through the whole compatibility matrix and see if there are other profiles that can be slimmed down by removing such redundancy.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reviewed-by: Tobias Brox <tobias@redpill-linpro.com>
Bedework 5 answers a PUT with ETag: %22...%22, where a GET gives the
quoted form, and refuses the encoded form in If-Match with 412, so every
second save() of an object raised ETagMismatchError.  A leading %22 is
not legal entity-tag syntax (RFC 9110 section 8.8.3), so
_update_tag_props() decodes it.

That error had mis-graded three Bedework 5 features, re-measured with
the fix: cross-calendar duplicate UIDs and attendee PARTSTAT edits work,
and sync-token works except for deletes.  The new save.etag and
save-load.mutable.if-match-wildcard are recorded for both profiles.

Prompt: Work with [a handover document from another session] - it's needed with some probes to detect the bedework etag problems, mitigation in the caldav library to handle it, and an issue report in the bedework repository
Followup-Prompt: (output of `pytest -k 'bede and compat'` pasted: attendee-partstat and duplicate-uid.cross-calendar observed full on Bedework 5, if-match-wildcard observed unsupported on Bedework 3)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reviewed-by: Tobias Brox <tobias@redpill-linpro.com>
A server-peculiarity can be neither supported, unsupported or observable, but "is
a write observable once the server answered it with success" can.
full is yes, unsupported is an asynchronous server, fragile one too
fast to observe reliably.  The post-write sleep stays in the delay key,
now read through the new write_delay() helper.  As a server-feature it
is compared against what caldav-server-tester measures.  write-delay
shipped in 3.3.0, so it is still accepted and translated with a
DeprecationWarning.  Bedework 5 is declared fragile, since the probe
reads its writes back at once.

Prompt: write-delay in compatbiliity_hints.py (sic) is a
"server-peculiarity".  It does not make sense to have it "supported" or
"unsupported".  However, maybe we can reverse it and turn it into a
"feature" - "synchronized_write" or something like that.  "supported"
then means that the observable state should be updated when getting
"200 OK", while "unsupported" means there may be a delay between the
"200 OK" and until the state is stored and observable.  "fragile" would
mean that write-operations are expected to be async, but that they are
fast enough that it can be hard to observe it.  Does it make sense?  If
it makes sense, please implement.  [caldav-server-tester] also needs
some work.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reviewed-by: Tobias Brox <tobias@redpill-linpro.com>
Bedework 5 answers an expanded calendar-query with one DAV:response per
recurrence instance, all under the href of the resource - RFC 4918
section 14.24 forbids that.  The multistatus parser let each later
calendar-data overwrite the earlier, so every expanded search lost all
but the last occurrence.  Repeated calendar-data is now merged into one
VCALENDAR, skipping components already present (a VTIMEZONE is matched
by its TZID).  This fixes testRecurringDateSearch and
testRecurringDateWithExceptionSearch, sync and async, against
Bedework 5.

Prompt: There is a handover document here, another agent has been working with it, but it did not do the "B and C", recurring-search failures for the bedework server
Followup-Prompt: Is this actually a bug in the caldav library and not in Bedework?  Caldav library should be fixed.  If Bedework behaves according to the RFC, but still differently from other servers, then let the server checker probe and add a behaviour note for search.recurrences.expanded perhaps?

AI-assisted: Claude Opus 5 via Claude Code
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reviewed-by: Tobias Brox <tobias@redpill-linpro.com>
Hand edits by Tobias, with some AI-based QA.  The unreleased CHANGELOG
is cut down and tightened.  Tests no longer lock the write-delay amounts
for Infomaniak and Bedework 5, Bedework's time-based sync-tokens are
configured so the tests sleep, and the synchronous-write documentation
is shortened.

The Cyrus start.sh no longer runs `docker-compose down` before `up -d`,
which killed a live server and wiped a concurrent test run's state.

Prompt: It sounds like an asymmetry that cyrus runs down when starting it [docker-compose down in tests/docker-test-servers/cyrus/start.sh], please fix.
Followup-Prompt: (comment from the review process) The next three commits can most certainly be squashed together - even if they are quite unreleated (sic), they are all minor commits.  38807ec also seems like a minor commit.  a913b81 also seems like something that can be folded neatly into such a commit

AI-assisted: Claude Opus 5 via Claude Code
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reviewed-by: Tobias Brox <tobias@redpill-linpro.com>
pytest's short summary shows only the first line of an assertion
message, which for testCheckCompatibility was a bare "compatibility
mismatches:".  It now carries the count and the first mismatch.

Prompt: The output from the compatibility test looks like this:
(nine "FAILED ...::testCheckCompatibility - AssertionError:
compatibility mismatches:" lines pasted) The annoying part here is
that the error is terminated after the colon.  Now I have to dig
through the (huge!) test logs to see exactly what kind of
compatibility failure it is and it's hard to get an overview.  Can
the test be fixed so (at least the first)e (sic) mismatch is shown in
the overview?  (be aware that some other agent may be working with
caldav-server-tester at the moment)

AI-assisted: Claude Opus 5 via Claude Code
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reviewed-by: Tobias Brox <tobias@redpill-linpro.com>
caldav-server-tester now also PUTs If-Match: * to a missing object,
which shows Bedework 3.10.3 and 5.0.0 have it backwards (412 on an
existing object, 201 on a missing one) and SOGo ignores it; both are
"broken".  Zimbra compares "*" as a literal etag and stays
"unsupported", now noting that If-None-Match: * overwrites.  The
feature description names the three shapes.


Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reviewed-by: Tobias Brox <tobias@redpill-linpro.com>
The server tester's new probes caught four profiles out, each checked
against the server source or a direct request.  Xandikos and SOGo
ignore the component set given at MKCALENDAR, Radicale 3.8.0 compares
If-Match: * as a literal etag, and OX ignores the i;octet collation -
declared working since b5e26c4, which was wrong.

Prompts: (Code-review questions and comments on work done in the caldav-server-tester.  Follow-up-conversations urging it to do a proper job there.  This resulted in some changes in the server compatibility matrix)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reviewed-by: Tobias Brox <tobias@redpill-linpro.com>
`TestAsyncForNextcloud::test_set_calendar_properties` failed on every
run after the first with "server advertises delete- and
create-calendar, but no fresh calendar".  Nextcloud moves deleted
calendars to a trashbin (`delete-calendar.free-namespace` fragile), so
`afix_calendar()` reuses the calendar from the previous run.  The
`created` assert from 812d6df now applies only where deletion frees
the URL; elsewhere the test checks it got its own calendar back.  The
display name is put back after the rename, as the sync test does, so
the rename is a real change on a reused calendar too.  Run twice on
Nextcloud and once on Radicale and Xandikos; a Nextcloud container
still carrying the old "hooray-async" name fails once, then passes.

Prompt: This found (sic) while doing checks in caldav: FAILED tests/test_async_integration.py::TestAsyncForNextcloud::test_set_calendar_properties - AssertionError: server advertises delete- and create-calendar, but no fresh calendar
is it an async/sync problem?

Followup-Prompt: [do the recommended fix: assert `created` and the creation-time name only when free-namespace is supported]
Followup-Prompt: (review findings accepted: put the display name back so the rename is not a no-op on a reused calendar, check the reused calendar is the test's own, correct the 812d6df attribution, verify on a second Nextcloud run)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reviewed-by: Tobias Brox <tobias@redpill-linpro.com>
The profile claimed the server-tester does not catch
`delete-calendar.free-namespace`.  It does, and grades the docker
Nextcloud `full`, because setup_nextcloud.sh disables the trashbin; that
step now warns when it fails instead of passing silently.  `fragile`
stays, as "varies by deployment", and `ecloud` - a default install - is
graded unsupported.  Re-enabling the trashbin was considered, but
setup_nextcloud.sh records UNIQUE violations from soft-deleted objects
on Nextcloud 33, and Nextcloud's `X-NC-CalDAV-No-Trashbin` header, which
the library does not send, only covers calendar deletes.  The robur
profile also grades `save.etag` broken (a malformed etag), added by
hand.

Prompt: [add a delete-calendar.free-namespace probe to caldav-server-tester, as the Nextcloud profile TODO says it is not caught]

Followup-Prompt: isn't it better to turn on the thrashbin (sic) feature again, and test the nextcloud as a true nextcloud server?  At the other hand, I remember having an issue on ecloud that I frequently have to enter the web-ui and manually "empty" the thrashbin (sic) ... and we had similar problems with tests going into a bad state towards the local nextcloud, requiring a nextcloud server restart.  Think a bit if there are any better solutions here, if not then go for the comment-only solution

Followup-Prompt: [hand-edited comments in the code]
Followup-Prompt: (comment from the review process) Check the latest commit, maybe this is fixed already [on the "Calendar deletion goes to trashbin" comment, which was not; now qualified to a trashbin-enabled install]
Followup-Prompt: (review findings accepted: link the Nextcloud source for the header claim, warn when the setup cannot disable the trashbin)
Followup-Prompt: (review findings accepted: link Calendar.php for the calendar-only limit, narrow the reason not to re-enable the trashbin to what was observed, move the ecloud line off the rate-limit TODO, correct three facts in the free-namespace comment)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reviewed-by: Tobias Brox <tobias@redpill-linpro.com>
The 3.3.1 section was missing three generic fixes (207 on MKCALENDAR,
percent-encoded PUT ETag, expanded instances sharing one href) and the
profile regrades that change is_supported() answers.  The roadmap is
brought in line with the issue tracker: the multiget ask of
#487 shipped in 3.3.0,
and closed issues are ticked off.

Prompt: 3.3.1 goes out tomorrow with the current state of this branch.  Please check with the roadmap what things have been closed in 3.3.0 and 3.3.1.
Followup-Prompt: look into my comments [inline comments on a report about the above]
Followup-Prompt: I've done some changes to the ROADMAP, please piggyback my changes into the next commit
Followup-Prompt: Please verify and close [#487]
Followup-Prompt: Please make it consistent [the multiget section number and priority in the roadmap summary table]
Followup-Prompt: Update to "updated 2026-08-15" or "2026-08-16". (sic) [the roadmap header date; 2026-09-15 used]
Followup-Prompt: Please fix [missing entries and a redundant sentence in the 3.3.1 CHANGELOG]

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

AI Prompts:
claude-sonnet-4-6: <task-notification> <task-id>bcc4vsw9w</task-id> <tool-use-id>toolu_01YACdKxjRB7MZhcXnW2qqTA</tool-use-id> <output-file>/tmp/claude-7385/-home-tobias-caldav/3934293f-61bf-4490-a98f-eaf07b9abd94/tasks/bcc4vsw9w.output</output-file> <status>completed</status> <summary>Background command "Open issue comment draft for approval" completed (exit code 0)</summary> </task-notification>
* Link syntax fix, fixes #712
* The github-code-quality-bot flagged an except-block doing nothing without comments, copied the justification code comments from the equivalent sync code
@tobixen
tobixen marked this pull request as ready for review September 16, 2026 05:51
@tobixen
tobixen merged commit 111ae14 into master Sep 16, 2026
18 checks passed
@tobixen
tobixen deleted the compatibility branch September 18, 2026 10:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant