calternaldav: break it every way (conformance suites, real Apple clients, cursed data, concurrency, isolation, DoS) #457

Closed
opened 2026-09-29 13:56:46 +00:00 by kayg · 39 comments
Owner

Owner (2026-09-29): "You need to try to break calternaldav as many ways as possible. I'm sure there will be a lot of hit and trial!"

Scope: every standard-protocol adapter that exists on dev (28ac39f9 or later):

  • CalDAV: events, Reminders VTODO, the per-area Journal calendars (#356), Untagged, and the retired journal/ (410);
  • WebDAV: Files, including sidecars once #420 lands;
  • configuration profiles and App Password scopes (#395).
    webcal (#431) and the Notes IMAP bridge (#428) are not built yet. When they land, this probe must be extended, so leave hooks.
    This is an explicit owner request for extended adversarial work, beyond the one-round-per-merge rule. Work in rounds: attack, fix, add a regression test, attack again, until a full round finds nothing new of blocking class, or 4 hours pass.

Attack surface (be creative; these are starting points)

  • Protocol conformance tools: the WebDAV litmus suite; Apple's CalDAVTester (ccs-caldavtester) where it runs; cadaver; rclone (serve and copy both ways); vdirsyncer; Thunderbird-style REPORT queries (calendar-query with time-range and prop filters, calendar-multiget, sync-collection with stale, forged and huge tokens); curl for raw malformed requests.
  • Real Apple clients on the macOS VM (netbird ssh --no-browser calternal@10.69.69.21, cua-driver; the admin login is in ~/calternal-private/macos-vm/credentials.env, never printed). Do things users do: rapid edits, offline edits then reconnect, the same event edited on the web and the Mac at once, drag between area calendars mid-sync, delete a calendar, change the account password, revoke the App Password mid-sync, huge attachments, 5,000 events, and a recurring event with 500 exceptions.
  • Cursed data:
    • Unicode (NFC/NFD, RTL, zero-width, emoji ZWJ sequences, CRLF injection in SUMMARY);
    • folded lines at every byte offset, including inside multi-byte chars;
    • a 10 MB and a 100 MB ICS;
    • a VCALENDAR with 100k components;
    • RRULE bombs (FREQ=SECONDLY without COUNT, BYSETPOS abuse, UNTIL before DTSTART);
    • bad or unknown TZIDs and VTIMEZONE with 10k observances;
    • floating vs UTC vs zoned mixing, DST gaps and overlaps;
    • VALARM storms (1,000 alarms), nested components, duplicate UIDs across collections, a UID with a slash or "..", a UID of 10k chars;
    • DESCRIPTION with Markdown that could inject Log-line syntax (- 09:00 fake #area/x ^blockid), and #area/ injection in SUMMARY.
  • Paths and resources: .., %2e%2e, double encoding, overlong UTF-8, NUL, a trailing dot or space, case-folding collisions, a 4 KB path segment, a MOVE and COPY destination across Users or outside the Home, Destination on another host, Overwrite: F races, LOCK and UNLOCK misuse, and a PROPPATCH on protected properties.
  • Concurrency: 50 parallel PUTs to the same resource with and without If-Match; interleaved MOVE and DELETE; sync-collection during a bulk import; a PUT during an area rename.
  • Auth and isolation (#331 class): another User's principal, calendar home and resource IDs by guess or enumeration; timing and size oracles on 404 vs 403; App Password scopes (a Calendar-only password trying WebDAV and the reverse); revoked credentials; Basic auth with huge or malformed headers.
  • Resource exhaustion: slowloris on PROPFIND, depth-infinity PROPFIND on a big tree, REPORT with 10k hrefs, gzip bombs in request bodies, and many open sync tokens. The server must stay responsive for other Users (noisy-neighbour check).

Rules

  • Blocking (fix now, with a regression test in the crate or in tests/adversarial/): any 5xx, crash or panic, data loss or corruption (including lossy round-trips of fields we promise to keep), cross-user access or inference, a sync collision, accepted hostile input that later breaks a client, a DoS.
  • Non-blocking (file an issue): cosmetic or odd-but-harmless behaviour.
  • Extend tests/adversarial/ (the DAV probe, attack.py) permanently with every new attack, so the weekly hunt reruns them.
  • Commit per finding: the repro, then the fix, then the test. Findings go on #393 or #356 by area, or a new issue per root cause.
  • Gates per crate for everything touched; the adversarial round passes at the end.
  • Do not measure performance on the perf-test VM. Run servers on the build host.
## Owner (2026-09-29): "You need to try to break calternaldav as many ways as possible. I'm sure there will be a lot of hit and trial!" Scope: every standard-protocol adapter that exists on dev (28ac39f9 or later): - **CalDAV:** events, Reminders VTODO, the per-area Journal calendars (#356), Untagged, and the retired `journal/` (410); - **WebDAV:** Files, including sidecars once #420 lands; - **configuration profiles and App Password scopes** (#395). webcal (#431) and the Notes IMAP bridge (#428) are not built yet. When they land, this probe must be extended, so leave hooks. This is an explicit owner request for **extended** adversarial work, beyond the one-round-per-merge rule. Work in rounds: attack, fix, add a regression test, attack again, until a full round finds nothing new of blocking class, or 4 hours pass. ## Attack surface (be creative; these are starting points) - **Protocol conformance tools:** the WebDAV `litmus` suite; Apple's **CalDAVTester** (ccs-caldavtester) where it runs; `cadaver`; `rclone` (serve and copy both ways); `vdirsyncer`; Thunderbird-style REPORT queries (calendar-query with time-range and prop filters, calendar-multiget, sync-collection with stale, forged and huge tokens); `curl` for raw malformed requests. - **Real Apple clients on the macOS VM** (`netbird ssh --no-browser calternal@10.69.69.21`, cua-driver; the admin login is in `~/calternal-private/macos-vm/credentials.env`, never printed). Do things users do: rapid edits, offline edits then reconnect, the same event edited on the web and the Mac at once, drag between area calendars mid-sync, delete a calendar, change the account password, revoke the App Password mid-sync, huge attachments, 5,000 events, and a recurring event with 500 exceptions. - **Cursed data:** - Unicode (NFC/NFD, RTL, zero-width, emoji ZWJ sequences, CRLF injection in SUMMARY); - folded lines at every byte offset, including inside multi-byte chars; - a 10 MB and a 100 MB ICS; - a VCALENDAR with 100k components; - RRULE bombs (FREQ=SECONDLY without COUNT, BYSETPOS abuse, UNTIL before DTSTART); - bad or unknown TZIDs and VTIMEZONE with 10k observances; - floating vs UTC vs zoned mixing, DST gaps and overlaps; - VALARM storms (1,000 alarms), nested components, duplicate UIDs across collections, a UID with a slash or "..", a UID of 10k chars; - DESCRIPTION with Markdown that could inject Log-line syntax (`- 09:00 fake #area/x ^blockid`), and `#area/` injection in SUMMARY. - **Paths and resources:** `..`, `%2e%2e`, double encoding, overlong UTF-8, NUL, a trailing dot or space, case-folding collisions, a 4 KB path segment, a MOVE and COPY destination across Users or outside the Home, Destination on another host, Overwrite: F races, LOCK and UNLOCK misuse, and a PROPPATCH on protected properties. - **Concurrency:** 50 parallel PUTs to the same resource with and without If-Match; interleaved MOVE and DELETE; sync-collection during a bulk import; a PUT during an area rename. - **Auth and isolation (#331 class):** another User's principal, calendar home and resource IDs by guess or enumeration; timing and size oracles on 404 vs 403; App Password scopes (a Calendar-only password trying WebDAV and the reverse); revoked credentials; Basic auth with huge or malformed headers. - **Resource exhaustion:** slowloris on PROPFIND, depth-infinity PROPFIND on a big tree, REPORT with 10k hrefs, gzip bombs in request bodies, and many open sync tokens. The server must stay responsive for **other** Users (noisy-neighbour check). ## Rules - Blocking (fix now, with a regression test in the crate or in `tests/adversarial/`): any 5xx, crash or panic, data loss or corruption (including lossy round-trips of fields we promise to keep), cross-user access or inference, a sync collision, accepted hostile input that later breaks a client, a DoS. - Non-blocking (file an issue): cosmetic or odd-but-harmless behaviour. - Extend `tests/adversarial/` (the DAV probe, `attack.py`) permanently with every new attack, so the weekly hunt reruns them. - Commit per finding: the repro, then the fix, then the test. Findings go on #393 or #356 by area, or a new issue per root cause. - Gates per crate for everything touched; the adversarial round passes at the end. - **Do not measure performance on the perf-test VM.** Run servers on the build host.
Author
Owner

Starting break-dav on branch job/break-dav at base 28ac39f917. I read CLAUDE.md, CONTEXT.md, and the CalDAV/area calendar/App Password decisions in docs/DESIGN.md. I will run the local DAV probes first, add permanent attack cases, then fix blocking findings with regressions. The Mac verification service is active, so I will leave that VM alone until it becomes inactive.

Starting break-dav on branch job/break-dav at base 28ac39f917f3dedd44dec2e863ee2854d64c2d5a. I read CLAUDE.md, CONTEXT.md, and the CalDAV/area calendar/App Password decisions in docs/DESIGN.md. I will run the local DAV probes first, add permanent attack cases, then fix blocking findings with regressions. The Mac verification service is active, so I will leave that VM alone until it becomes inactive.
Author
Owner

Progress: committed permanent DAV probes in c9a8b6e4, 272b0431, b99af777, 75d61125, and d4047ca2. They cover Files WebDAV via a real scoped App Password, reciprocal Calendar/Files scope denial and revocation, foreign-host COPY, protected PROPPATCH, conditional PUT races, encoded and long paths, large iCalendar and REPORT bodies, and a Reminders VTODO round trip plus alarm storm. Python syntax and six DAV probe contract tests pass. I merged dev once at 8c77fd11; the current local server build is in progress before the live round. No server defect is claimed yet.

Progress: committed permanent DAV probes in c9a8b6e4, 272b0431, b99af777, 75d61125, and d4047ca2. They cover Files WebDAV via a real scoped App Password, reciprocal Calendar/Files scope denial and revocation, foreign-host COPY, protected PROPPATCH, conditional PUT races, encoded and long paths, large iCalendar and REPORT bodies, and a Reminders VTODO round trip plus alarm storm. Python syntax and six DAV probe contract tests pass. I merged dev once at 8c77fd11; the current local server build is in progress before the live round. No server defect is claimed yet.
Author
Owner

Live round on the merged dev build found one blocking protocol response: a 100 MiB Journal PUT received HTTP 502 from the local proxy while the server stayed alive. The request body exceeded the 64 KiB DAV limit, but the adapter read it before checking Content-Length; the proxy began streaming after 100 Continue and saw the upstream close. The 10 MiB case returned 413. I added an early declared-length check to Journal and Reminders PUT, with a crate regression and the permanent 100 MiB probe; validation is running now.

The Files WebDAV conditional PUT race produced one 204, five 412 and two 405, with one complete final body and no collision. I filed the odd but non-blocking response as #459. The public proxy normalized %2e%2e before routing and returned 404, so the probe now tests the backend directly for its 400 rejection while accepting either safe public response.

Live round on the merged dev build found one blocking protocol response: a 100 MiB Journal PUT received HTTP 502 from the local proxy while the server stayed alive. The request body exceeded the 64 KiB DAV limit, but the adapter read it before checking Content-Length; the proxy began streaming after `100 Continue` and saw the upstream close. The 10 MiB case returned 413. I added an early declared-length check to Journal and Reminders PUT, with a crate regression and the permanent 100 MiB probe; validation is running now. The Files WebDAV conditional PUT race produced one 204, five 412 and two 405, with one complete final body and no collision. I filed the odd but non-blocking response as #459. The public proxy normalized `%2e%2e` before routing and returned 404, so the probe now tests the backend directly for its 400 rejection while accepting either safe public response.
Author
Owner

Data-loss finding (deploy blocker), reported by the money-md job's adversarial round on dev: the Reminders completion path loses an existing DESCRIPTION. Completing a VTODO drops the reminder's notes (evidence posted on #393). This is on dev and not yet deployed. It must be fixed, with an Apple replay regression (complete a reminder that has multi-line notes; the notes survive in Markdown and on the next GET), before the #356/#393 deploy. Job break-dav (#457) owns the fix; job mac-verify must include the scenario in its GO/NO-GO.

**Data-loss finding (deploy blocker)**, reported by the money-md job's adversarial round on dev: the Reminders **completion path loses an existing DESCRIPTION**. Completing a VTODO drops the reminder's notes (evidence posted on #393). This is on dev and not yet deployed. It must be fixed, with an Apple replay regression (complete a reminder that has multi-line notes; the notes survive in Markdown and on the next GET), before the #356/#393 deploy. Job break-dav (#457) owns the fix; job mac-verify must include the scenario in its GO/NO-GO.
Author
Owner

The post-fix full DAV-only round passed against the merged local server at head d3c51b47. Output: DAV Apple property, write-capability, MKCALENDAR and adversarial probes completed; ODD #459 conditional PUT losers returned 405: [204, 405, 409, 412, 412, 412, 412, 412]; WebDAV scripted probes passed. The direct backend returned HTTP 413 for the 100 MiB declared Journal PUT after the early-length fix. Calendar/Reminders/WebDAV/App Password scope and revocation probes had no blocking finding. Remaining work is final Rust gates and cleanup.

The post-fix full DAV-only round passed against the merged local server at head d3c51b47. Output: `DAV Apple property, write-capability, MKCALENDAR and adversarial probes completed`; `ODD #459 conditional PUT losers returned 405: [204, 405, 409, 412, 412, 412, 412, 412]`; `WebDAV scripted probes passed`. The direct backend returned HTTP 413 for the 100 MiB declared Journal PUT after the early-length fix. Calendar/Reminders/WebDAV/App Password scope and revocation probes had no blocking finding. Remaining work is final Rust gates and cleanup.
Author
Owner

Final server Clippy gate reached an unrelated warning from the merged dev Search change in crates/calternal-fs/src/root.rs:379: value == [b'1'] triggers clippy::byte-char-slices under -D warnings. I changed only that expression to value == *b"1" (the same byte comparison) so the required gate can run. This is a syntax-only fix outside the DAV crate; I am running the calternal-fs crate gates before committing it.

Final server Clippy gate reached an unrelated warning from the merged dev Search change in `crates/calternal-fs/src/root.rs:379`: `value == [b'1']` triggers `clippy::byte-char-slices` under `-D warnings`. I changed only that expression to `value == *b"1"` (the same byte comparison) so the required gate can run. This is a syntax-only fix outside the DAV crate; I am running the `calternal-fs` crate gates before committing it.
Author
Owner

Finder read-only mount (from #409): on the macOS VM, Finder/mount_webdav mounted the calternal WebDAV share read-only, while the rclone baseline mounted read-write. macOS mounts WebDAV read-write only when OPTIONS advertises DAV: 1, 2 (class 2 = LOCK/UNLOCK) and LOCK works. Verify our OPTIONS DAV header and LOCK/UNLOCK on /dav/files, and fix it so Finder mounts read-write (litmus 'locks' suite passing). Then prove it on the Mac: mount, create, rename and delete files from Finder. Separately, the 'Operation not permitted' errors on both servers came from macOS privacy (TCC network-volume access for the ssh or cua session), not from the servers. Grant access through System Settings via cua-driver (the admin login is in ~/calternal-private/macos-vm/credentials.env) so Finder copies can be timed. Owner: break-dav (#457).

**Finder read-only mount (from #409):** on the macOS VM, Finder/mount_webdav mounted the calternal WebDAV share **read-only**, while the rclone baseline mounted read-write. macOS mounts WebDAV read-write only when OPTIONS advertises `DAV: 1, 2` (class 2 = LOCK/UNLOCK) and LOCK works. Verify our OPTIONS `DAV` header and LOCK/UNLOCK on /dav/files, and fix it so Finder mounts read-write (litmus 'locks' suite passing). Then prove it on the Mac: mount, create, rename and delete files from Finder. Separately, the 'Operation not permitted' errors on both servers came from macOS privacy (TCC network-volume access for the ssh or cua session), not from the servers. Grant access through System Settings via cua-driver (the admin login is in ~/calternal-private/macos-vm/credentials.env) so Finder copies can be timed. Owner: break-dav (#457).
Author
Owner

The unrelated calternal-fs Clippy warning is fixed in 53375c48. It changes only [b'1'] to *b"1" for the Search readiness marker comparison. cargo fmt --check, cargo clippy -p calternal-fs --all-targets -- -D warnings, and cargo test -p calternal-fs passed (42 tests). Server Clippy is rerunning.

The unrelated `calternal-fs` Clippy warning is fixed in 53375c48. It changes only `[b'1']` to `*b"1"` for the Search readiness marker comparison. `cargo fmt --check`, `cargo clippy -p calternal-fs --all-targets -- -D warnings`, and `cargo test -p calternal-fs` passed (42 tests). Server Clippy is rerunning.
Author
Owner

Final report for #457

Branch: job/break-dav
Head: 53375c48d2
Base: 28ac39f9; merged dev once at 8c77fd11.

Built:

  • Extended the permanent DAV hunt in tests/adversarial/attack.py and tests/adversarial/webdav.py: Calendar and Reminders oversized bodies, 100k components, 10k REPORT hrefs, forged huge sync tokens, Files encoded/oversized paths, cross-host COPY, protected PROPPATCH, descendant MOVE/COPY, conditional PUT and create-only COPY races, App Password scope isolation and revocation. Added hooks for webcal #431 and Notes IMAP #428 when built.
  • In crates/calternal-dav/src/protocol.rs, Journal and Reminders PUT now return 413 for declared bodies over 64 KiB before requesting the body; chunked bodies remain bounded by the reader. Added a unit regression.
  • In crates/calternal-fs/src/root.rs, resolved a syntax-only Clippy warning from merged dev.

Final live DAV-only round (exit 0), output verbatim:

finish 200
login web 200 installation 200
cookies [ "__Host-calternal_session secure=true httpOnly=true sameSite=Lax" ]
invite 200
second user finish 200
fixture passkey login requests: 30/30
DAV Apple property, write-capability, MKCALENDAR and adversarial probes completed
ODD #459 conditional PUT losers returned 405: [204, 405, 409, 412, 412, 412, 412, 412]
WebDAV scripted probes passed

Gate output verbatim:

cargo fmt --check
exit=0
python3 -m unittest discover -s tests/adversarial -p 'test_dav_probe.py' -v
Ran 6 tests in 0.001s
OK
cargo clippy -p calternal-dav --all-targets -- -D warnings
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 20s
cargo test -p calternal-dav
test result: ok. 32 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.15s
test result: ok. 30 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.06s
cargo clippy -p calternal-fs --all-targets -- -D warnings
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 32.77s
cargo test -p calternal-fs
test result: ok. 39 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 16.04s
test result: ok. 42 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.55s
cargo clippy -p calternal-server --all-targets -- -D warnings
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 8m 32s
cargo test -p calternal-server
test result: ok. 82 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 21.05s
cargo clippy --workspace --all-targets -- -D warnings
error: only one of 'runtime-async-std' or 'runtime-tokio' features must be enabled
error: could not compile `async-imap` (lib) due to 14 previous errors
cargo test --workspace
error: only one of 'runtime-async-std' or 'runtime-tokio' features must be enabled
error: could not compile `async-imap` (lib) due to 8 previous errors; 1 warning emitted

The full workspace failure is in vendored Mail async-imap feature unification, outside this DAV job; filed #463. The tests and server remain green per crate. cargo clean output: Removed 18558 files, 10.2GiB total.

Known gaps: Mac verification was unavailable while codex-cal-mac-verify.service was active; #420 sidecars, #431 webcal and #428 Notes IMAP had not landed. litmus, cadaver, rclone, vdirsyncer and CalDAVTester were not completed in this round. SLOW-only observations under build-host load were treated as non-blocking per owner rule. Conditional PUT losers can return safe but misleading 405/409; filed #459. No new blocking issue remained in the final live round.

Decisions beyond DESIGN: direct backend raw probes bypass the local browser proxy for encoded traversal and early oversized-request rejection, because that proxy normalizes paths and can translate an upstream early close into 502. A 409 upload reservation conflict is an acceptable conditional race loser only when exactly one writer succeeds and final bytes match its body. No pushes, deploys or merges into dev were made.

Final report for #457 Branch: job/break-dav Head: 53375c48d27bc199d57b40605ad81b69559e5cdb Base: 28ac39f9; merged dev once at 8c77fd11. Built: - Extended the permanent DAV hunt in tests/adversarial/attack.py and tests/adversarial/webdav.py: Calendar and Reminders oversized bodies, 100k components, 10k REPORT hrefs, forged huge sync tokens, Files encoded/oversized paths, cross-host COPY, protected PROPPATCH, descendant MOVE/COPY, conditional PUT and create-only COPY races, App Password scope isolation and revocation. Added hooks for webcal #431 and Notes IMAP #428 when built. - In crates/calternal-dav/src/protocol.rs, Journal and Reminders PUT now return 413 for declared bodies over 64 KiB before requesting the body; chunked bodies remain bounded by the reader. Added a unit regression. - In crates/calternal-fs/src/root.rs, resolved a syntax-only Clippy warning from merged dev. Final live DAV-only round (exit 0), output verbatim: ``` finish 200 login web 200 installation 200 cookies [ "__Host-calternal_session secure=true httpOnly=true sameSite=Lax" ] invite 200 second user finish 200 fixture passkey login requests: 30/30 DAV Apple property, write-capability, MKCALENDAR and adversarial probes completed ODD #459 conditional PUT losers returned 405: [204, 405, 409, 412, 412, 412, 412, 412] WebDAV scripted probes passed ``` Gate output verbatim: ``` cargo fmt --check exit=0 python3 -m unittest discover -s tests/adversarial -p 'test_dav_probe.py' -v Ran 6 tests in 0.001s OK cargo clippy -p calternal-dav --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 20s cargo test -p calternal-dav test result: ok. 32 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.15s test result: ok. 30 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.06s cargo clippy -p calternal-fs --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 32.77s cargo test -p calternal-fs test result: ok. 39 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 16.04s test result: ok. 42 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.55s cargo clippy -p calternal-server --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 8m 32s cargo test -p calternal-server test result: ok. 82 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 21.05s cargo clippy --workspace --all-targets -- -D warnings error: only one of 'runtime-async-std' or 'runtime-tokio' features must be enabled error: could not compile `async-imap` (lib) due to 14 previous errors cargo test --workspace error: only one of 'runtime-async-std' or 'runtime-tokio' features must be enabled error: could not compile `async-imap` (lib) due to 8 previous errors; 1 warning emitted ``` The full workspace failure is in vendored Mail async-imap feature unification, outside this DAV job; filed #463. The tests and server remain green per crate. `cargo clean` output: ` Removed 18558 files, 10.2GiB total`. Known gaps: Mac verification was unavailable while codex-cal-mac-verify.service was active; #420 sidecars, #431 webcal and #428 Notes IMAP had not landed. litmus, cadaver, rclone, vdirsyncer and CalDAVTester were not completed in this round. SLOW-only observations under build-host load were treated as non-blocking per owner rule. Conditional PUT losers can return safe but misleading 405/409; filed #459. No new blocking issue remained in the final live round. Decisions beyond DESIGN: direct backend raw probes bypass the local browser proxy for encoded traversal and early oversized-request rejection, because that proxy normalizes paths and can translate an upstream early close into 502. A 409 upload reservation conflict is an acceptable conditional race loser only when exactly one writer succeeds and final bytes match its body. No pushes, deploys or merges into dev were made.
Author
Owner

Round 2 started on job/break-dav from origin/dev at 9bf3d549b41f5fe97c29148220a1a9c484faf63d. I am rebuilding the branch without the accidental #400 merge and keeping only the listed DAV probe commits. This round will add the Reminders DESCRIPTION completion regression and fix, implement real class 2 locks on /dav/files with lock-aware writes, run litmus locks, then run the per-crate gates and one adversarial round. I will attempt the Mac verification only when codex-cal-mac-verify.service is inactive and the Mac VM lock is available.

Round 2 started on `job/break-dav` from `origin/dev` at `9bf3d549b41f5fe97c29148220a1a9c484faf63d`. I am rebuilding the branch without the accidental #400 merge and keeping only the listed DAV probe commits. This round will add the Reminders DESCRIPTION completion regression and fix, implement real class 2 locks on `/dav/files` with lock-aware writes, run litmus `locks`, then run the per-crate gates and one adversarial round. I will attempt the Mac verification only when `codex-cal-mac-verify.service` is inactive and the Mac VM lock is available.
Author
Owner

The #457 Apple replay now reproduces the Reminders data-loss finding. apple_reminder_completion_keeps_multiline_description_for_get_and_report creates a VTODO from put-multiline-notes.ics, then PUTs completion without DESCRIPTION; the following GET fails its assertion because DESCRIPTION:First line\\nSecond line is gone. The root cause is NotesRemindersProvider::update_existing: it calls set_task_body with None when the incoming VTODO omits DESCRIPTION, and set_task_body(None) removes the Task prose. I am adding a regression against the real Notes provider so it checks the Markdown file and production GET/REPORT path.

The #457 Apple replay now reproduces the Reminders data-loss finding. `apple_reminder_completion_keeps_multiline_description_for_get_and_report` creates a VTODO from `put-multiline-notes.ics`, then PUTs completion without DESCRIPTION; the following GET fails its assertion because `DESCRIPTION:First line\\nSecond line` is gone. The root cause is `NotesRemindersProvider::update_existing`: it calls `set_task_body` with `None` when the incoming VTODO omits DESCRIPTION, and `set_task_body(None)` removes the Task prose. I am adding a regression against the real Notes provider so it checks the Markdown file and production GET/REPORT path.
Author
Owner

Round 2 finding: /dav/files currently advertises DAV: 1 and omits LOCK/UNLOCK, so Finder cannot negotiate class 2. The route uses a dav-server locksystem only for PUT/DELETE handlers and has no route lock table configured. I am implementing real expiring tokens and lock checks for the custom mutation routes as well, then I will run the DAV adversarial probe and litmus locks suite.

Round 2 finding: `/dav/files` currently advertises `DAV: 1` and omits LOCK/UNLOCK, so Finder cannot negotiate class 2. The route uses a `dav-server` locksystem only for PUT/DELETE handlers and has no route lock table configured. I am implementing real expiring tokens and lock checks for the custom mutation routes as well, then I will run the DAV adversarial probe and litmus locks suite.
Author
Owner

Decision for the lease-durability question added to docs/research/file-protocols.md: keep File DAV locks in the single server process. Every lease has a finite timeout capped at 600 seconds (600 seconds when the client omits a timeout). A process restart clears the table, so clients must acquire a new lock. This is the smallest choice consistent with the single-writer server; Finder and litmus will verify the protocol behavior.

Decision for the lease-durability question added to `docs/research/file-protocols.md`: keep File DAV locks in the single server process. Every lease has a finite timeout capped at 600 seconds (600 seconds when the client omits a timeout). A process restart clears the table, so clients must acquire a new lock. This is the smallest choice consistent with the single-writer server; Finder and litmus will verify the protocol behavior.
Author
Owner

RFC 4918 §9.11 allows UNLOCK to name any resource within a depth-infinity lock. The implementation required the lock root URL, so that valid request failed. I changed unlock lookup to accept a descendant only when the token belongs to a depth-infinity lock and added unlock_accepts_a_resource_within_infinite_lock_scope as a regression.

RFC 4918 §9.11 allows UNLOCK to name any resource within a depth-infinity lock. The implementation required the lock root URL, so that valid request failed. I changed unlock lookup to accept a descendant only when the token belongs to a depth-infinity lock and added `unlock_accepts_a_resource_within_infinite_lock_scope` as a regression.
Author
Owner

The initial lock table had no per-User limit, so an authenticated lock flood could retain an unbounded number of live entries during the finite lease. I bounded each User to 1,024 active leases, return 507 when new locks exceed that limit, and added a regression that fills the cap, checks User isolation, and confirms expiry frees capacity.

The initial lock table had no per-User limit, so an authenticated lock flood could retain an unbounded number of live entries during the finite lease. I bounded each User to 1,024 active leases, return 507 when new locks exceed that limit, and added a regression that fills the cap, checks User isolation, and confirms expiry frees capacity.
Author
Owner

Starting round 2 on branch job/break-dav, rebuilt from origin/dev at 369ab6a2f9fc673e3564b94857fbecfeb04df404. Replayed only the 14 job commits listed in the resume instructions; current head is 0a67b539051a4341c23341906f9dc5482aefade7. I will reproduce and fix the Reminders DESCRIPTION loss, verify/complete WebDAV class 2 locks, then run the specified crate gates and one adversarial round.

Starting round 2 on branch `job/break-dav`, rebuilt from `origin/dev` at `369ab6a2f9fc673e3564b94857fbecfeb04df404`. Replayed only the 14 job commits listed in the resume instructions; current head is `0a67b539051a4341c23341906f9dc5482aefade7`. I will reproduce and fix the Reminders DESCRIPTION loss, verify/complete WebDAV class 2 locks, then run the specified crate gates and one adversarial round.
Author
Owner

Finding on #457: the new crates/plugins/notes/tests/apple_replay.rs::completing_reminder_without_description_preserves_notes replay creates the Apple put-multiline-notes.ics VTODO, completes it without DESCRIPTION, and fails after the completion PUT because the actual Markdown Task no longer contains First line\nSecond line. This confirms the #393 data-loss report against the production Notes provider. I am fixing omitted-versus-empty DESCRIPTION handling and will keep this regression checking Markdown, GET, and REPORT.

Finding on #457: the new `crates/plugins/notes/tests/apple_replay.rs::completing_reminder_without_description_preserves_notes` replay creates the Apple `put-multiline-notes.ics` VTODO, completes it without DESCRIPTION, and fails after the completion PUT because the actual Markdown Task no longer contains `First line\nSecond line`. This confirms the #393 data-loss report against the production Notes provider. I am fixing omitted-versus-empty DESCRIPTION handling and will keep this regression checking Markdown, GET, and REPORT.
Author
Owner

Round 2 report for #457 (break-dav)

Branch job/break-dav, head 660776c101d7449329388f726ef63a2417f11050. It is rebuilt on origin/dev and does not include #400. origin/dev was merged twice, the last time at d86a05b50 (mac-verify, merge-batch #392, webdav-perf). The one conflict was in calternal-dav/src/files.rs. I kept both sides: the webdav-perf 412 passthrough and the class 2 DAV header.

Fixed

  1. Deploy blocker (a), Reminders notes. When an Apple completion PUT leaves out DESCRIPTION, the notes now stay in place. Before, update_existing handled a missing DESCRIPTION as "clear" and deleted the Task prose. Now a missing DESCRIPTION keeps the notes, and an empty one still clears them (crates/plugins/notes/src/tasks_dav.rs). Regressions: crates/plugins/notes/tests/apple_replay.rs runs the real Notes provider on Apple's put-multiline-notes.ics, completes the reminder without DESCRIPTION, and checks the Markdown, GET and REPORT. crates/calternal-dav/tests/apple_replay.rs::apple_reminder_completion_keeps_multiline_description_for_get_and_report covers the wire flow.
  2. Deploy blocker (b), Finder read-write. /dav/files now supports RFC 4918 class 2:
    • DAV: 1, 2 and LOCK/UNLOCK are offered only to Full and Write credentials.
    • Lock tokens are opaque and expiring. The timeout is at most 600 s. Refresh and unlock are supported, including through a member URL of a depth-infinity lock.
    • A write without the lock token gets 423 Locked. This applies to PUT, MKCOL, DELETE, MOVE and COPY, on both source and destination.
    • Locks are scoped per User, with at most 1,024 live leases per User.
    • One User's lock changes and writes run one at a time.
    • The server's App Password route filter also blocked LOCK/UNLOCK. On a live server they never reached the handler. That is fixed now (wire.rs, with a test).
  3. Crash found by litmus. dav-server 0.11's If-header parser panics on an unterminated </[ token. The request task died and the proxy returned 502. The Files route now checks the header with the same token rules and returns 400 before dispatch. There is a unit test and a route regression.

Mac proof (macOS 27 VM, macvm.lock held; mac-verify was inactive)

  • Finder "Connect to Server" mounted http://localhost:<port>/dav/files/<user>/ over a reverse tunnel. The mount is read-write: mount does not show read-only.
  • Finder File > New Folder created untitled folder on the server (MKCOL).
  • On the mount, these all worked: create, write, append, rename, copy, rename a folder, move into a folder, delete a file, delete a folder recursively. A UTF-8 file written from the Mac read back byte-exact through the server.
  • The TCC grant was needed: System Settings > Files & Folders > NetBird > Network Volumes is now ON. No admin password was asked for. The grant stays on the VM for future jobs.
  • Cleanup: the mount is removed, the temporary App Passwords went with the throwaway server, and the lock is released.

litmus locks: 36/41 pass

The 5 known failures, all 4xx:

  • owner_modify ×3 does PROPPATCH of a dead property. Files WebDAV does not store dead properties, so it returns 403.
  • complex_cond_put and fail_complex_cond_put: litmus 0.13 cuts its If line at a fixed buffer, and our ETag is 64 hex digits long. The server correctly returns 400 for the cut header.

tests/adversarial/webdav.py accepts only these exact results. Any 5xx or other failure is a finding. This is covered by unit tests in test_dav_probe.py.

Adversarial DAV round (merged build, ADVERSARIAL_DAV_ONLY=1 with litmus): exit 0

DAV Apple property, write-capability, MKCALENDAR and adversarial probes completed
<- summary for `locks': of 41 tests run: 36 passed, 5 failed. 87.8%
KNOWN litmus owner_modify: 403 Forbidden
KNOWN litmus complex_cond_put: 400 Bad Request
KNOWN litmus fail_complex_cond_put: 400 Bad Request
KNOWN litmus owner_modify: 403 Forbidden
KNOWN litmus owner_modify: 403 Forbidden
WebDAV scripted probes passed
exit=0

Gates (verbatim, after the last merge; calternal-fs is not changed on this branch)

$ cargo fmt --check
exit=0
$ python3 -m unittest test_dav_probe -v
Ran 9 tests in 0.044s
OK
$ cargo clippy -p calternal-dav --all-targets -- -D warnings
 Finished `dev` profile [unoptimized + debuginfo] target(s) in 18.73s
$ cargo test -p calternal-dav
test result: ok. 40 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.10s
test result: ok. 33 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s
$ cargo clippy -p calternal-plugin-notes --all-targets -- -D warnings
 Finished `dev` profile [unoptimized + debuginfo] target(s) in 7.25s
$ cargo test -p calternal-plugin-notes --no-fail-fast
test result: ok. 123 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 42.23s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.30s
$ cargo clippy -p calternal-server --all-targets -- -D warnings
 Finished `dev` profile [unoptimized + debuginfo] target(s) in 20.53s
$ cargo test -p calternal-server
test result: ok. 84 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 5.96s

Before the last merge, notes::tests::vtodo_wire_upgrade_rotates_sync_epoch_once failed on origin/dev. The test pops only the last migration, and 0019 came after 0018. It passes after merging d86a05b50. cargo clean removed 11.7 GiB.

Remaining

  • Reminders on the real Mac is not done. There is no CalDAV account on the VM for a throwaway server, and setting one up through Internet Accounts via cua did not fit the time box. The fix is proven only by replaying Apple's recorded wire request against the real provider.
  • The Apple rapid-edit, offline and concurrent attacks on the Mac are not done.
  • Files WebDAV has no PROPPATCH or dead-property support. Finder does not need it, but class 1 strictly requires it.

Decisions

  • Locks live in memory in the single server process. A server restart drops them, and clients lock again. The lease is capped at 600 s, with at most 1,024 per User.
  • One User's WebDAV writes, including PUT uploads, run one at a time. This makes lock checks atomic. Two different Users never block each other.
  • Only Full and Write credentials get class 2. Read and upload-only credentials still get DAV: 1.
## Round 2 report for #457 (break-dav) Branch `job/break-dav`, head `660776c101d7449329388f726ef63a2417f11050`. It is rebuilt on `origin/dev` and does not include #400. `origin/dev` was merged twice, the last time at `d86a05b50` (mac-verify, merge-batch #392, webdav-perf). The one conflict was in `calternal-dav/src/files.rs`. I kept both sides: the webdav-perf 412 passthrough and the class 2 `DAV` header. ### Fixed 1. **Deploy blocker (a), Reminders notes.** When an Apple completion PUT leaves out DESCRIPTION, the notes now stay in place. Before, `update_existing` handled a missing DESCRIPTION as "clear" and deleted the Task prose. Now a missing DESCRIPTION keeps the notes, and an empty one still clears them (`crates/plugins/notes/src/tasks_dav.rs`). Regressions: `crates/plugins/notes/tests/apple_replay.rs` runs the real Notes provider on Apple's `put-multiline-notes.ics`, completes the reminder without DESCRIPTION, and checks the Markdown, GET and REPORT. `crates/calternal-dav/tests/apple_replay.rs::apple_reminder_completion_keeps_multiline_description_for_get_and_report` covers the wire flow. 2. **Deploy blocker (b), Finder read-write.** `/dav/files` now supports RFC 4918 class 2: - `DAV: 1, 2` and LOCK/UNLOCK are offered only to Full and Write credentials. - Lock tokens are opaque and expiring. The timeout is at most 600 s. Refresh and unlock are supported, including through a member URL of a depth-infinity lock. - A write without the lock token gets 423 Locked. This applies to PUT, MKCOL, DELETE, MOVE and COPY, on both source and destination. - Locks are scoped per User, with at most 1,024 live leases per User. - One User's lock changes and writes run one at a time. - The server's App Password route filter also blocked LOCK/UNLOCK. On a live server they never reached the handler. That is fixed now (`wire.rs`, with a test). 3. **Crash found by litmus.** dav-server 0.11's If-header parser panics on an unterminated `<`/`[` token. The request task died and the proxy returned 502. The Files route now checks the header with the same token rules and returns 400 before dispatch. There is a unit test and a route regression. ### Mac proof (macOS 27 VM, macvm.lock held; mac-verify was inactive) - Finder "Connect to Server" mounted `http://localhost:<port>/dav/files/<user>/` over a reverse tunnel. The mount is **read-write**: `mount` does not show `read-only`. - Finder File > New Folder created `untitled folder` on the server (MKCOL). - On the mount, these all worked: create, write, append, rename, copy, rename a folder, move into a folder, delete a file, delete a folder recursively. A UTF-8 file written from the Mac read back byte-exact through the server. - The TCC grant was needed: System Settings > Files & Folders > NetBird > **Network Volumes** is now ON. No admin password was asked for. The grant stays on the VM for future jobs. - Cleanup: the mount is removed, the temporary App Passwords went with the throwaway server, and the lock is released. ### litmus `locks`: 36/41 pass The 5 known failures, all 4xx: - `owner_modify` ×3 does PROPPATCH of a dead property. Files WebDAV does not store dead properties, so it returns 403. - `complex_cond_put` and `fail_complex_cond_put`: litmus 0.13 cuts its If line at a fixed buffer, and our ETag is 64 hex digits long. The server correctly returns 400 for the cut header. `tests/adversarial/webdav.py` accepts only these exact results. Any 5xx or other failure is a finding. This is covered by unit tests in `test_dav_probe.py`. ### Adversarial DAV round (merged build, `ADVERSARIAL_DAV_ONLY=1` with litmus): exit 0 ``` DAV Apple property, write-capability, MKCALENDAR and adversarial probes completed <- summary for `locks': of 41 tests run: 36 passed, 5 failed. 87.8% KNOWN litmus owner_modify: 403 Forbidden KNOWN litmus complex_cond_put: 400 Bad Request KNOWN litmus fail_complex_cond_put: 400 Bad Request KNOWN litmus owner_modify: 403 Forbidden KNOWN litmus owner_modify: 403 Forbidden WebDAV scripted probes passed exit=0 ``` ### Gates (verbatim, after the last merge; calternal-fs is not changed on this branch) ``` $ cargo fmt --check exit=0 $ python3 -m unittest test_dav_probe -v Ran 9 tests in 0.044s OK $ cargo clippy -p calternal-dav --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 18.73s $ cargo test -p calternal-dav test result: ok. 40 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.10s test result: ok. 33 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s $ cargo clippy -p calternal-plugin-notes --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 7.25s $ cargo test -p calternal-plugin-notes --no-fail-fast test result: ok. 123 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 42.23s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.30s $ cargo clippy -p calternal-server --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 20.53s $ cargo test -p calternal-server test result: ok. 84 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 5.96s ``` Before the last merge, `notes::tests::vtodo_wire_upgrade_rotates_sync_epoch_once` failed on origin/dev. The test pops only the last migration, and 0019 came after 0018. It passes after merging `d86a05b50`. `cargo clean` removed 11.7 GiB. ### Remaining - **Reminders on the real Mac is not done.** There is no CalDAV account on the VM for a throwaway server, and setting one up through Internet Accounts via cua did not fit the time box. The fix is proven only by replaying Apple's recorded wire request against the real provider. - The Apple rapid-edit, offline and concurrent attacks on the Mac are not done. - Files WebDAV has no PROPPATCH or dead-property support. Finder does not need it, but class 1 strictly requires it. ### Decisions - Locks live in memory in the single server process. A server restart drops them, and clients lock again. The lease is capped at 600 s, with at most 1,024 per User. - One User's WebDAV writes, including PUT uploads, run one at a time. This makes lock checks atomic. Two different Users never block each other. - Only Full and Write credentials get class 2. Read and upload-only credentials still get `DAV: 1`.
Author
Owner

Merged into dev at 55a2f90fe and pushed. Deploy status is on #203.

Merged into dev at 55a2f90fe and pushed. Deploy status is on #203.
kayg closed this issue 2026-09-30 00:29:54 +00:00
Author
Owner

Start caldav-stress on job/caldav-stress, base 0dc772c369. This job's explicit perf-VM instruction takes precedence over the older issue text. Issue is already closed; its state will stay unchanged. VM SSH works but flock -n /root/perf.lock returned 1. Shared release binary (04:42) predates branch base (05:55 UTC); build locally. WebDAV stays with #476 and #429. Scope here: isolated, bounded performance and normal concurrency correctness; no exploit payloads or crash automation.

Start caldav-stress on job/caldav-stress, base 0dc772c3697ea9bd01822c26440c32206d472715. This job's explicit perf-VM instruction takes precedence over the older issue text. Issue is already closed; its state will stay unchanged. VM SSH works but flock -n /root/perf.lock returned 1. Shared release binary (04:42) predates branch base (05:55 UTC); build locally. WebDAV stays with #476 and #429. Scope here: isolated, bounded performance and normal concurrency correctness; no exploit payloads or crash automation.
Author
Owner

Progress: a6d64c5c4 adds an isolated DAV read/projection harness and pre-run decision rules; 4c6d7c39e adds a bounded normal 8-writer Reminders conditional-edit check to the weekly runner. Four evidence-check tests pass. origin/dev merge: Already up to date. cargo fmt --check exit=0. Shared older release compatibility check projected exactly 100 Log entries + 20 VTODOs across 20 areas; initial/unchanged sync requests passed, and two full listings matched. This is a build-host compatibility sample with one repetition and unknown shared-binary source SHA; it is NOT a performance baseline. VM lock remains held. Local source-matched release build is still compiling. Webcal/CardDAV source adapters were not found in this branch. No production bug has been established.

Progress: a6d64c5c4 adds an isolated DAV read/projection harness and pre-run decision rules; 4c6d7c39e adds a bounded normal 8-writer Reminders conditional-edit check to the weekly runner. Four evidence-check tests pass. origin/dev merge: Already up to date. cargo fmt --check exit=0. Shared older release compatibility check projected exactly 100 Log entries + 20 VTODOs across 20 areas; initial/unchanged sync requests passed, and two full listings matched. This is a build-host compatibility sample with one repetition and unknown shared-binary source SHA; it is NOT a performance baseline. VM lock remains held. Local source-matched release build is still compiling. Webcal/CardDAV source adapters were not found in this branch. No production bug has been established.
Author
Owner

Execution limits: perf lock checks returned 1, so no VM measurement ran. Current-source release compilation did not finish and was stopped (exit 130) at the gate phase to avoid concurrent compiler load. Full workspace clippy was attempted once with a 300-second limit and ended with exit 124 while dependencies compiled. Full workspace cargo test is now running once with the same bound. This round is incomplete and cannot establish a VM baseline or approve a merge. Partial read/concurrency evidence and an opt-in incremental/polling harness are committed; latest head e8f8190b15. Final report will give exact gate outcomes and remaining cases.

Execution limits: perf lock checks returned 1, so no VM measurement ran. Current-source release compilation did not finish and was stopped (exit 130) at the gate phase to avoid concurrent compiler load. Full workspace clippy was attempted once with a 300-second limit and ended with exit 124 while dependencies compiled. Full workspace cargo test is now running once with the same bound. This round is incomplete and cannot establish a VM baseline or approve a merge. Partial read/concurrency evidence and an opt-in incremental/polling harness are committed; latest head e8f8190b1581da7c3a103c0dfc167887deea69f1. Final report will give exact gate outcomes and remaining cases.
Author
Owner

Final report (partial)

Branch: job/caldav-stress. Head: 3b22300df1ede6267c4b0105aade607151c0c501. Base: 0dc772c3697ea9bd01822c26440c32206d472715.

Built an isolated read/projection harness with optional 1/100/10k incremental sync checks and fifty-client polling with five VTODO writers. Added the bounded eight-writer persisted-winner check to the weekly runner and nine Python tests for fixture and evidence validation. No Rust, API or UI source changed.

Files:

  • docs/perf/caldav-baseline.md
  • docs/perf/runs/2026-09-30-caldav-457-compatibility.json
  • docs/perf/runs/2026-09-30-caldav-457.md
  • tests/adversarial/dav_concurrency.py
  • tests/adversarial/run.sh
  • tests/perf/caldav_scale.py
  • tests/perf/test_caldav_scale.py
  • tests/perf/upload_scale.py

CalDAV round #457 — 2026-09-30

State: incomplete. No perf VM baseline is set.

The perf VM lock was held at the access checks. No VM measurement ran.
The source-matched release build did not finish. It was stopped (exit 130)
when final gates began, to keep compiler concurrency low.
The VM is x86_64. The harness is copied to /root/caldav-stress-457.

Local compatibility evidence

These are smoke checks, not benchmark results. The shared release binary is
older than the branch base. Its source SHA is unknown. It has SHA-256
3efae4228ff71f9614fa30a872abb573c4667999e6b5e5f4286b1476ed5ad54b. The fixture has 100 Log entries and 20 VTODOs.
It projected all 120 resources. Two complete listings matched after reads.
One request per case cannot estimate latency percentiles. Host start load:
[55.02490234375, 65.02099609375, 67.74658203125].

Request HTTP Response bytes Single request ms
home:propfind-depth1 207 13077 129.997
area:propfind-depth1 207 3510 127.049
reminders:propfind-depth1 207 11749 154.795
area:query-month 207 165 134.678
area:query-year 207 165 106.505
area:initial-sync 207 2278 78.5
area:unchanged-sync 207 373 73.301
reminders:initial-sync 207 7269 34.805
reminders:unchanged-sync 207 189 95.521

A second local compatibility run timed out during listing checks. Its state
is incomplete. This does not establish a protocol defect under host load.

A separate bounded real-server Reminders check passed on the same shared
binary:

PASS bounded real-server conditional edit: {"writers": 8, "winners": 1, "precondition_failures": 7, "readback": true}

Requested cases

Case Evidence state
50k Log entries, 5k VTODOs, twenty areas Fixture unit test passed. Full VM run pending.
PROPFIND depth 1, month/year REPORT, initial sync Local small read profile passed. Full VM run pending.
Unchanged incremental sync Local small read profile passed.
Sync after 1, 100 and 10k changes Optional runner added. Live verification pending.
Fifty clients and five writers Optional polling runner added. Live verification pending.
Conditional edit Eight writers: one persisted winner and seven 412s. Shared binary only.
Moves between areas Not covered by this runner.
1,000 concurrent PUTs and hostile ICS/RRULEs Not implemented in this job. No exploit or crash automation.
CardDAV and Webcal Source adapters not found at the branch base. Not measured.
WebDAV Follow #476 and #429. No duplicate measurements.

No new production bug was established. No bug issue was created.

Decisions

  • Follow the job prompt for the perf VM; the older issue text says build host.
  • Keep the already closed issue state unchanged.
  • Use an isolated loopback server and standard-library Python. No dependency changes.
  • Seed fixture files while the server is stopped; measured changes use the API.
  • Disable semantic-model downloads for DAV measurements. Discard startup output
    before it reaches disk, because it can contain a setup token.
  • Record per-area queries separately from the total Home resource count.
  • Use twenty samples by default and label the coarse p99. A future valid VM run
    sets the baseline. Flag later interleaved p95 or peak RSS increases above 20%.
  • Keep WebDAV lock and fsync performance work with #476 and #429.

The decision rules and run command are in docs/perf/caldav-baseline.md.
Do not use this partial round to approve a merge or claim stress coverage.

The compatibility JSON is in 2026-09-30-caldav-457-compatibility.json. It
includes sampled CPU and RSS for each small request. Its explicit
valid_performance_baseline: false flag prevents use as a VM baseline.

Validation

The Python and shell checks passed. The Rust gates did not finish; each
was attempted once for the workspace with a 300-second limit. Exit 124
means timeout during dependency compilation, not a passing gate. No Rust
source changed. The production web build completed; no UI source changed.

Gate output, verbatim:

cargo fmt --check exit=0
cargo clippy --all-targets -- -D warnings exit=124
cargo test exit=124
bash -n tests/adversarial/run.sh exit=0
git diff --check exit=0
----------------------------------------------------------------------
Ran 9 tests in 5.795s

OK
PASS bounded real-server conditional edit: {"writers": 8, "winners": 1, "precondition_failures": 7, "readback": true}

The DAV probe contract unit suite also passed (9 tests). The full hostile
input round was not run in this job. No merge or deployment is approved.
Cargo output and generated web build output were removed at the end.

No push, deploy, or branch merge was made. The required git fetch origin and git merge origin/dev reported Already up to date. Issue state remains unchanged.

# Final report (partial) Branch: `job/caldav-stress`. Head: `3b22300df1ede6267c4b0105aade607151c0c501`. Base: `0dc772c3697ea9bd01822c26440c32206d472715`. Built an isolated read/projection harness with optional 1/100/10k incremental sync checks and fifty-client polling with five VTODO writers. Added the bounded eight-writer persisted-winner check to the weekly runner and nine Python tests for fixture and evidence validation. No Rust, API or UI source changed. Files: - `docs/perf/caldav-baseline.md` - `docs/perf/runs/2026-09-30-caldav-457-compatibility.json` - `docs/perf/runs/2026-09-30-caldav-457.md` - `tests/adversarial/dav_concurrency.py` - `tests/adversarial/run.sh` - `tests/perf/caldav_scale.py` - `tests/perf/test_caldav_scale.py` - `tests/perf/upload_scale.py` # CalDAV round #457 — 2026-09-30 State: incomplete. No perf VM baseline is set. The perf VM lock was held at the access checks. No VM measurement ran. The source-matched release build did not finish. It was stopped (exit 130) when final gates began, to keep compiler concurrency low. The VM is x86_64. The harness is copied to `/root/caldav-stress-457`. ## Local compatibility evidence These are smoke checks, not benchmark results. The shared release binary is older than the branch base. Its source SHA is unknown. It has SHA-256 `3efae4228ff71f9614fa30a872abb573c4667999e6b5e5f4286b1476ed5ad54b`. The fixture has 100 Log entries and 20 VTODOs. It projected all 120 resources. Two complete listings matched after reads. One request per case cannot estimate latency percentiles. Host start load: `[55.02490234375, 65.02099609375, 67.74658203125]`. | Request | HTTP | Response bytes | Single request ms | | --- | --- | ---: | ---: | | home:propfind-depth1 | 207 | 13077 | 129.997 | | area:propfind-depth1 | 207 | 3510 | 127.049 | | reminders:propfind-depth1 | 207 | 11749 | 154.795 | | area:query-month | 207 | 165 | 134.678 | | area:query-year | 207 | 165 | 106.505 | | area:initial-sync | 207 | 2278 | 78.5 | | area:unchanged-sync | 207 | 373 | 73.301 | | reminders:initial-sync | 207 | 7269 | 34.805 | | reminders:unchanged-sync | 207 | 189 | 95.521 | A second local compatibility run timed out during listing checks. Its state is incomplete. This does not establish a protocol defect under host load. A separate bounded real-server Reminders check passed on the same shared binary: ```text PASS bounded real-server conditional edit: {"writers": 8, "winners": 1, "precondition_failures": 7, "readback": true} ``` ## Requested cases | Case | Evidence state | | --- | --- | | 50k Log entries, 5k VTODOs, twenty areas | Fixture unit test passed. Full VM run pending. | | PROPFIND depth 1, month/year REPORT, initial sync | Local small read profile passed. Full VM run pending. | | Unchanged incremental sync | Local small read profile passed. | | Sync after 1, 100 and 10k changes | Optional runner added. Live verification pending. | | Fifty clients and five writers | Optional polling runner added. Live verification pending. | | Conditional edit | Eight writers: one persisted winner and seven 412s. Shared binary only. | | Moves between areas | Not covered by this runner. | | 1,000 concurrent PUTs and hostile ICS/RRULEs | Not implemented in this job. No exploit or crash automation. | | CardDAV and Webcal | Source adapters not found at the branch base. Not measured. | | WebDAV | Follow #476 and #429. No duplicate measurements. | No new production bug was established. No bug issue was created. ## Decisions - Follow the job prompt for the perf VM; the older issue text says build host. - Keep the already closed issue state unchanged. - Use an isolated loopback server and standard-library Python. No dependency changes. - Seed fixture files while the server is stopped; measured changes use the API. - Disable semantic-model downloads for DAV measurements. Discard startup output before it reaches disk, because it can contain a setup token. - Record per-area queries separately from the total Home resource count. - Use twenty samples by default and label the coarse p99. A future valid VM run sets the baseline. Flag later interleaved p95 or peak RSS increases above 20%. - Keep WebDAV lock and fsync performance work with #476 and #429. The decision rules and run command are in `docs/perf/caldav-baseline.md`. Do not use this partial round to approve a merge or claim stress coverage. The compatibility JSON is in `2026-09-30-caldav-457-compatibility.json`. It includes sampled CPU and RSS for each small request. Its explicit `valid_performance_baseline: false` flag prevents use as a VM baseline. ## Validation The Python and shell checks passed. The Rust gates did not finish; each was attempted once for the workspace with a 300-second limit. Exit 124 means timeout during dependency compilation, not a passing gate. No Rust source changed. The production web build completed; no UI source changed. Gate output, verbatim: ```text cargo fmt --check exit=0 cargo clippy --all-targets -- -D warnings exit=124 cargo test exit=124 bash -n tests/adversarial/run.sh exit=0 git diff --check exit=0 ---------------------------------------------------------------------- Ran 9 tests in 5.795s OK PASS bounded real-server conditional edit: {"writers": 8, "winners": 1, "precondition_failures": 7, "readback": true} ``` The DAV probe contract unit suite also passed (9 tests). The full hostile input round was not run in this job. No merge or deployment is approved. Cargo output and generated web build output were removed at the end. No push, deploy, or branch merge was made. The required `git fetch origin` and `git merge origin/dev` reported `Already up to date.` Issue state remains unchanged.
Author
Owner

Final check clarification: six new DAV evidence tests were added; the combined DAV/upload benchmark suite has nine passing tests. The separate existing DAV probe contract suite also has nine passing tests. Cargo cleanup completed: Removed 3784 files, 1.0GiB total; cargo clean exit=0. Generated web output and Python bytecode were removed. The worktree is clean. Head remains 3b22300df1. The VM measurements and baseline remain pending; this is a partial report, not completion of the stress round.

Final check clarification: six new DAV evidence tests were added; the combined DAV/upload benchmark suite has nine passing tests. The separate existing DAV probe contract suite also has nine passing tests. Cargo cleanup completed: `Removed 3784 files, 1.0GiB total`; `cargo clean exit=0`. Generated web output and Python bytecode were removed. The worktree is clean. Head remains 3b22300df1ede6267c4b0105aade607151c0c501. The VM measurements and baseline remain pending; this is a partial report, not completion of the stress round.
Author
Owner

Resume #457 on job/caldav-stress at 3b22300df1; branch base 0dc772c369. Use the supplied release binary and web build; no builds. The first nonblocking VM lock attempt returned 1, so no measurement ran. Scope: isolated normal-load performance and concurrency correctness; exploit payloads and deliberate DoS storms remain outside this run. Issue state stays unchanged.

Resume #457 on job/caldav-stress at 3b22300df1ede6267c4b0105aade607151c0c501; branch base 0dc772c3697ea9bd01822c26440c32206d472715. Use the supplied release binary and web build; no builds. The first nonblocking VM lock attempt returned 1, so no measurement ran. Scope: isolated normal-load performance and concurrency correctness; exploit payloads and deliberate DoS storms remain outside this run. Issue state stays unchanged.
Author
Owner

Progress: 1626daaa0 validates each polling client cache with changed ETags and deletion tombstones; 91dcdbcbc adds Apple-shaped area moves during five normal writers and bounded 1/100-href multiget checks. Nine evidence tests pass, including an accepted MOVE whose omitted sync delta must fail. Supplied binary SHA-256: 7f98931bde5141750b4eee9e8053dcce6cc90b0841d1208601d5bf0dd84d1bc8. Binary and web build are copied to /root/caldav-stress-457. At 07:40 UTC, the VM lock is held by PID 1267207, bash bench/run.sh --full --search --measure-only --runs 5 in the perf-367 job. Our flock waits at most 600 seconds; no measurement has started. No builds were run. No release binary exists at /mnt/hdd/targets/jobs/webcal-431/release/calternal-server; webcal measurement is pending. WebDAV findings stay with #476 and #429.

Progress: 1626daaa0 validates each polling client cache with changed ETags and deletion tombstones; 91dcdbcbc adds Apple-shaped area moves during five normal writers and bounded 1/100-href multiget checks. Nine evidence tests pass, including an accepted MOVE whose omitted sync delta must fail. Supplied binary SHA-256: 7f98931bde5141750b4eee9e8053dcce6cc90b0841d1208601d5bf0dd84d1bc8. Binary and web build are copied to /root/caldav-stress-457. At 07:40 UTC, the VM lock is held by PID 1267207, bash bench/run.sh --full --search --measure-only --runs 5 in the perf-367 job. Our flock waits at most 600 seconds; no measurement has started. No builds were run. No release binary exists at /mnt/hdd/targets/jobs/webcal-431/release/calternal-server; webcal measurement is pending. WebDAV findings stay with #476 and #429.
Author
Owner

The first 600-second perf lock wait ended with exit 1 and no measurement. #367 held the lock throughout (PID 1267207, bench/run.sh --full --search --measure-only --runs 5). A single longer 1800-second wait is now queued. No lock was bypassed and no other process was stopped. Merge from origin/dev completed once without conflicts, at b13f6922fa (origin/dev 5474493b17). The benchmark still uses the explicitly supplied 0dc772c369 release binary; it is not a benchmark of the newer merged source.

The first 600-second perf lock wait ended with exit 1 and no measurement. #367 held the lock throughout (PID 1267207, bench/run.sh --full --search --measure-only --runs 5). A single longer 1800-second wait is now queued. No lock was bypassed and no other process was stopped. Merge from origin/dev completed once without conflicts, at b13f6922fa3e24861287c75314a2ae2c686bd022 (origin/dev 5474493b170f5d12b3d0fc9ccf5c3880e3d24bae). The benchmark still uses the explicitly supplied 0dc772c3697ea9bd01822c26440c32206d472715 release binary; it is not a benchmark of the newer merged source.
Author
Owner

The longer lock wait acquired /root/perf.lock at about 08:03 UTC. Full-scale measurement is now running on the copied 0dc772c36 release binary under flock. Load recorded inside the lock: 4.86 / 6.10 / 6.11. Command includes 50k Log entries, 5k Tasks, 20 samples, 1/100/10k incremental changes, fifty polling clients, five writers with area moves, and final convergence. No build ran. This is an execution update, not a passing result.

The longer lock wait acquired /root/perf.lock at about 08:03 UTC. Full-scale measurement is now running on the copied 0dc772c36 release binary under flock. Load recorded inside the lock: 4.86 / 6.10 / 6.11. Command includes 50k Log entries, 5k Tasks, 20 samples, 1/100/10k incremental changes, fifty polling clients, five writers with area moves, and final convergence. No build ran. This is an execution update, not a passing result.
Author
Owner

The first locked VM run reached seeded readiness in 263.586 seconds, with 3,653 fixture Daily notes. It then timed out at the 30-second request limit during fixture-projection, before the 55k resource count could be verified. No request timing rows were recorded. Load start 4.856 / 6.099 / 6.109; end 1.521 / 3.434 / 4.965. This is SLOW/incomplete evidence, not proof of a crash, 5xx or missing accepted write. One bounded 120-second request-limit attempt is now running under the VM lock to determine whether the read profile can complete. Binary remains the supplied 0dc772c36 release; no builds.

The first locked VM run reached seeded readiness in 263.586 seconds, with 3,653 fixture Daily notes. It then timed out at the 30-second request limit during fixture-projection, before the 55k resource count could be verified. No request timing rows were recorded. Load start 4.856 / 6.099 / 6.109; end 1.521 / 3.434 / 4.965. This is SLOW/incomplete evidence, not proof of a crash, 5xx or missing accepted write. One bounded 120-second request-limit attempt is now running under the VM lock to determine whether the read profile can complete. Binary remains the supplied 0dc772c36 release; no builds.
Author
Owner

Locked 120-second attempt verified all 55,000 resources across twenty areas and Reminders, and twenty-sample warm read timings. It stopped on a standard 100-href multiget returning 413. Filed #500 for that nonblocking 16 KiB REPORT-cap limitation. Commit 2fb723181 preserves expected 207 and the failed case, with a regression that 413 never becomes a passing timing row. Only the exact known size-limit 413 can continue to independent core checks; other status/content failures still stop. Thirteen Python tests pass. A corrected full core run is queued under the lock. No production source changed, no build ran, and no crash/5xx/data loss has been established.

Locked 120-second attempt verified all 55,000 resources across twenty areas and Reminders, and twenty-sample warm read timings. It stopped on a standard 100-href multiget returning 413. Filed #500 for that nonblocking 16 KiB REPORT-cap limitation. Commit 2fb723181 preserves expected 207 and the failed case, with a regression that 413 never becomes a passing timing row. Only the exact known size-limit 413 can continue to independent core checks; other status/content failures still stop. Thirteen Python tests pass. A corrected full core run is queued under the lock. No production source changed, no build ran, and no crash/5xx/data loss has been established.
Author
Owner

Final report — partial resumed round

Branch: job/caldav-stress. Head: c7525cde06b0b72b1f53caab0fe30e1e45d65a8f. No push or deployment. The required merge from origin/dev ran once without conflicts; no merge into dev or main was made. #457 state stays unchanged.

Built: per-client sync caches with deletion checks, Apple discovery and area MOVE replay, five writers at a normal cadence, bounded multiget checks, request-phase diagnostics and a recorded 30–120-second request bound. The #500 exception retains expected 207 and failed 413; it does not turn the rejected request into a passing test. No production source or dependency changed. No builds ran.

Measured: all 55,000 resources verified across twenty areas and Reminders; warm read table below. Filed #500 for the 100-href multiget size limit. The final corrected core run could not take the lock within 900 seconds, so incremental sync, fifty clients, live moves and conditional winner checks remain pending on the supplied release. A full baseline is not set. No crash, 5xx, data loss or sync collision was established. Hostile payloads and DoS storms were not implemented or run.

Authored files in this resume:

  • tests/perf/caldav_scale.py
  • tests/perf/test_caldav_scale.py
  • docs/perf/caldav-baseline.md
  • docs/perf/runs/2026-09-30-caldav-457-resume.md
  • docs/perf/runs/2026-09-30-caldav-457-resume-compatibility.json
  • docs/perf/runs/2026-09-30-caldav-457-resume-vm-30s.json
  • docs/perf/runs/2026-09-30-caldav-457-resume-vm-120s.json

CalDAV #457 resumed round — 2026-09-30

State: partial. Verified 55,000 projected resources and warm read timings on
the perf VM. Filed nonblocking multiget limit #500. The final core run did
not acquire the VM lock within 900 seconds. No full baseline is set.

The supplied release server and web build were copied to the perf VM.
No server or web build ran in this round. Server source:
0dc772c3697ea9bd01822c26440c32206d472715.
Binary SHA-256:
7f98931bde5141750b4eee9e8053dcce6cc90b0841d1208601d5bf0dd84d1bc8.
The VM files are in /root/caldav-stress-457.

Evidence before the VM run

The first 600-second lock wait returned exit 1. No measurement ran.
At 07:40 UTC, PID 1267207 held /root/perf.lock for #367:
bash bench/run.sh --full --search --measure-only --runs 5.
The second wait acquired the lock within its 1,800-second limit. A separate
120-second request-limit attempt also ran under that lock. The final corrected
core run then waited 900 seconds and returned exit 1 without starting. At
08:39 UTC, #367 still held the lock for its next Home profile. No lock was
bypassed. No other job was stopped or changed.

A local compatibility check used 100 Log entries and 20 Tasks. The server
became ready in 92.202 seconds after the fixture was seeded. A later request
timed out before the projection check completed. No request timing row was
recorded. The exact request phase was not recorded in this version of the
runner. The host load was 84.15 / 80.49 / 76.53 at the start.
This is not a VM baseline or evidence of a production defect.
The compatibility JSON has valid_performance_baseline: false.

Added checks

  • Each polling client applies ETags and deletion tombstones to its own cache.
    A final delta must make that cache match a full collection listing.
  • Five normal writers create, edit, read and delete Tasks at a 15-second
    cadence. Each also moves a small Log entry between its own pair of areas.
  • Area MOVE uses Apple's absolute Destination and source filename. The check
    follows the stable Location, verifies content, rejects duplicate copies,
    compares both sync deltas and preserves all seed ETags.
  • Principal and Home discovery replay the property selections in
    crates/calternal-dav/tests/apple_replay.rs.
  • Multiget requests cover 1 and 100 existing hrefs with ETags and VEVENT data.
  • Safe phase names and batch progress remain available if a request times out.

Coverage limits

Real Apple and DAVx5 Installations are not verified. No captured DAVx5 request
was found in apple_replay.rs. Standard multiget is not claimed as DAVx5 replay.
Hostile ICS/RRULE payloads and deliberate denial-of-service storms are outside
this run. No crash or exploit workload was added to the weekly probe.
CardDAV is absent from the supplied source. Webcal #431 is pending: no release
binary was available for that branch. A debug build does not meet this round's
release-build rule. No build was started to replace it.

WebDAV remains with #476 for
write serialisation and #429
for fsync. #476 has no measured results yet. The #429 measurements link to
docs/perf/webdav-2026-09-29.md; its Rclone comparison has different durability
and is not an equal-durability performance baseline.

Decisions

  • Use the supplied 0dc772c36 binary as requested, without a build. The required
    merge from origin/dev adds newer UI work; it does not change the measured
    binary. Do not label measurements as results for the merged head.
  • Keep the closed state of #457 unchanged.
  • Use disjoint area pairs for the five writers, so each move can prove that
    seed resources stayed unchanged during other writers' work.
  • Use a 15-second writer cadence. This tests normal concurrent use.
  • Keep local compatibility evidence separate from the VM baseline.
  • No dependency changes were needed.

First locked measurements

The 30-second attempt reached seeded readiness in 263.586 seconds, then
timed out during fixture projection. It recorded no timing rows. The
120-second attempt reached readiness in 262.263 seconds and verified all
55,000 resources. It collected the following warm read timings before the
100-href multiget returned 413. The full run was incomplete. Neither JSON
sets a full performance baseline. Each row has twenty samples; p99 is the
maximum of these samples, not a tail estimate. CPU is percent of one core.

Request p50 ms p95 ms p99 ms Response bytes Mean CPU % Peak RSS MiB
apple:principal-discovery 17.678 18.701 19.542 413 97.74 462.07
apple:calendar-home 17.541 18.460 18.595 668 96.13 462.07
home:propfind-depth1 78.509 86.824 90.312 13121 134.69 462.07
area:propfind-depth1 226.668 239.831 257.817 1380752 145.00 469.28
reminders:propfind-depth1 102.206 113.104 125.471 2790591 118.10 476.05
area:query-month 163.923 185.506 198.363 15433 150.62 476.43
area:query-year 158.334 179.216 188.982 170095 149.74 476.43
area:multiget-1 163.639 185.504 195.269 825 149.95 476.43

The month query returned 23 resources. The year query returned 256.
Each area starts with 2,500 entries. These timings do not describe a single
50,000-entry collection. All twenty areas and Reminders were counted.

The 100-href multiget limitation is filed as
#500. The runner keeps 207
as the expected result and records this 413 as a failed case. It can then
continue the independent sync and client checks. The new regression proves
that this 413 has no passing timing row. No existing expectation was changed.

Remaining case states

Requested case State in this resumed round
50k Log entries, 5k VTODOs, twenty areas Verified: 55,000 resources from real DAV listings.
Depth-1 PROPFIND and month/year query Measured: twenty samples per case in the table above.
Apple principal and Home discovery Measured and checked against the expected links.
One-href multiget Measured; ETag and VEVENT checked.
100-href multiget Failed: expected 207, actual 413. Filed #500.
Initial and unchanged sync Pending on the supplied release; the run stopped before these cases.
Incremental sync after 1, 100 and 10k changes Harness present; live full-scale checks pending.
Fifty polling clients and five writers Harness present; live full-scale checks pending.
Area moves and persisted conditional winner Harness present; live checks pending on the supplied release.
Real Apple and DAVx5 clients Not verified.
Hostile ICS/RRULE and DoS storms Not run or implemented.
Webcal and CardDAV Webcal release pending; CardDAV absent from the supplied source.
WebDAV Follow #476 and #429; no duplicate measurement.

No crash, 5xx, data loss or sync collision was established in this round.
The missing cases prevent a full stress-coverage claim. The read timings
cannot establish that write and sync behavior is correct.

Validation and cleanup

No Rust, API or UI source was changed by this job. Per-crate Clippy/tests and
web gates are not applicable to these Python and documentation changes. No
build ran. The required fetch and merge from origin/dev ran once, without
conflicts. Its source was 5474493b170f5d12b3d0fc9ccf5c3880e3d24bae.
The measured binary is still the supplied 0dc772c36 build.

Gate summary output, verbatim:

cargo fmt --check exit=0
----------------------------------------------------------------------
Ran 13 tests in 5.385s

OK
python scale tests exit=0
bash -n tests/adversarial/run.sh exit=0
git diff --check exit=0
     Removed 1 file, 356B total
cargo clean exit=0

The Python command was python3 -m unittest discover -s tests/perf -p 'test_*scale.py' -v, with TMPDIR in the worktree and bytecode writes off.
The added regressions check sync tombstones, failed property deltas, a missing
accepted-move delta and preservation of the failed 413 measurement. No existing
test expectation changed. Doc comments in both changed Python files were read
again before this report.

Local Cargo output and web build output were cleaned. The prepared shared
release and the VM copies remain available. The copied VM runner includes
the #500 classification and the 120-second request limit. When the lock is
available, the remaining normal-load command is:

# Run on the perf VM after connecting with netbird ssh.
cd /root/caldav-stress-457
flock /root/perf.lock sh -c '
  cat /proc/loadavg
  export TMPDIR="$PWD/target/tmp"
  python3 tests/perf/caldav_scale.py --server ./calternal-server \
    --data-root ./target/tmp --json ./fullscale-core.json \
    --commit 0dc772c3697ea9bd01822c26440c32206d472715 \
    --changes --poll-seconds 60 --request-timeout 120
'

The known #500 case remains failed. A completed core run with that finding
uses completed-with-findings, with core_checks_status: passed; it does not
label the 100-href case as passed.

Final report — partial resumed round Branch: `job/caldav-stress`. Head: `c7525cde06b0b72b1f53caab0fe30e1e45d65a8f`. No push or deployment. The required merge from origin/dev ran once without conflicts; no merge into dev or main was made. #457 state stays unchanged. Built: per-client sync caches with deletion checks, Apple discovery and area MOVE replay, five writers at a normal cadence, bounded multiget checks, request-phase diagnostics and a recorded 30–120-second request bound. The #500 exception retains expected 207 and failed 413; it does not turn the rejected request into a passing test. No production source or dependency changed. No builds ran. Measured: all 55,000 resources verified across twenty areas and Reminders; warm read table below. Filed [#500](https://git.kayg.org/kayg/calternal/issues/500) for the 100-href multiget size limit. The final corrected core run could not take the lock within 900 seconds, so incremental sync, fifty clients, live moves and conditional winner checks remain pending on the supplied release. A full baseline is not set. No crash, 5xx, data loss or sync collision was established. Hostile payloads and DoS storms were not implemented or run. Authored files in this resume: - `tests/perf/caldav_scale.py` - `tests/perf/test_caldav_scale.py` - `docs/perf/caldav-baseline.md` - `docs/perf/runs/2026-09-30-caldav-457-resume.md` - `docs/perf/runs/2026-09-30-caldav-457-resume-compatibility.json` - `docs/perf/runs/2026-09-30-caldav-457-resume-vm-30s.json` - `docs/perf/runs/2026-09-30-caldav-457-resume-vm-120s.json` # CalDAV #457 resumed round — 2026-09-30 State: partial. Verified 55,000 projected resources and warm read timings on the perf VM. Filed nonblocking multiget limit #500. The final core run did not acquire the VM lock within 900 seconds. No full baseline is set. The supplied release server and web build were copied to the perf VM. No server or web build ran in this round. Server source: `0dc772c3697ea9bd01822c26440c32206d472715`. Binary SHA-256: `7f98931bde5141750b4eee9e8053dcce6cc90b0841d1208601d5bf0dd84d1bc8`. The VM files are in `/root/caldav-stress-457`. ## Evidence before the VM run The first 600-second lock wait returned exit 1. No measurement ran. At 07:40 UTC, PID 1267207 held `/root/perf.lock` for #367: `bash bench/run.sh --full --search --measure-only --runs 5`. The second wait acquired the lock within its 1,800-second limit. A separate 120-second request-limit attempt also ran under that lock. The final corrected core run then waited 900 seconds and returned exit 1 without starting. At 08:39 UTC, #367 still held the lock for its next Home profile. No lock was bypassed. No other job was stopped or changed. A local compatibility check used 100 Log entries and 20 Tasks. The server became ready in 92.202 seconds after the fixture was seeded. A later request timed out before the projection check completed. No request timing row was recorded. The exact request phase was not recorded in this version of the runner. The host load was 84.15 / 80.49 / 76.53 at the start. This is not a VM baseline or evidence of a production defect. The compatibility JSON has `valid_performance_baseline: false`. ## Added checks - Each polling client applies ETags and deletion tombstones to its own cache. A final delta must make that cache match a full collection listing. - Five normal writers create, edit, read and delete Tasks at a 15-second cadence. Each also moves a small Log entry between its own pair of areas. - Area MOVE uses Apple's absolute Destination and source filename. The check follows the stable Location, verifies content, rejects duplicate copies, compares both sync deltas and preserves all seed ETags. - Principal and Home discovery replay the property selections in `crates/calternal-dav/tests/apple_replay.rs`. - Multiget requests cover 1 and 100 existing hrefs with ETags and VEVENT data. - Safe phase names and batch progress remain available if a request times out. ## Coverage limits Real Apple and DAVx5 Installations are not verified. No captured DAVx5 request was found in `apple_replay.rs`. Standard multiget is not claimed as DAVx5 replay. Hostile ICS/RRULE payloads and deliberate denial-of-service storms are outside this run. No crash or exploit workload was added to the weekly probe. CardDAV is absent from the supplied source. Webcal #431 is pending: no release binary was available for that branch. A debug build does not meet this round's release-build rule. No build was started to replace it. WebDAV remains with [#476](https://git.kayg.org/kayg/calternal/issues/476) for write serialisation and [#429](https://git.kayg.org/kayg/calternal/issues/429) for fsync. #476 has no measured results yet. The #429 measurements link to `docs/perf/webdav-2026-09-29.md`; its Rclone comparison has different durability and is not an equal-durability performance baseline. ## Decisions - Use the supplied 0dc772c36 binary as requested, without a build. The required merge from origin/dev adds newer UI work; it does not change the measured binary. Do not label measurements as results for the merged head. - Keep the closed state of #457 unchanged. - Use disjoint area pairs for the five writers, so each move can prove that seed resources stayed unchanged during other writers' work. - Use a 15-second writer cadence. This tests normal concurrent use. - Keep local compatibility evidence separate from the VM baseline. - No dependency changes were needed. ## First locked measurements The 30-second attempt reached seeded readiness in 263.586 seconds, then timed out during fixture projection. It recorded no timing rows. The 120-second attempt reached readiness in 262.263 seconds and verified all 55,000 resources. It collected the following warm read timings before the 100-href multiget returned 413. The full run was incomplete. Neither JSON sets a full performance baseline. Each row has twenty samples; p99 is the maximum of these samples, not a tail estimate. CPU is percent of one core. | Request | p50 ms | p95 ms | p99 ms | Response bytes | Mean CPU % | Peak RSS MiB | | --- | ---: | ---: | ---: | ---: | ---: | ---: | | apple:principal-discovery | 17.678 | 18.701 | 19.542 | 413 | 97.74 | 462.07 | | apple:calendar-home | 17.541 | 18.460 | 18.595 | 668 | 96.13 | 462.07 | | home:propfind-depth1 | 78.509 | 86.824 | 90.312 | 13121 | 134.69 | 462.07 | | area:propfind-depth1 | 226.668 | 239.831 | 257.817 | 1380752 | 145.00 | 469.28 | | reminders:propfind-depth1 | 102.206 | 113.104 | 125.471 | 2790591 | 118.10 | 476.05 | | area:query-month | 163.923 | 185.506 | 198.363 | 15433 | 150.62 | 476.43 | | area:query-year | 158.334 | 179.216 | 188.982 | 170095 | 149.74 | 476.43 | | area:multiget-1 | 163.639 | 185.504 | 195.269 | 825 | 149.95 | 476.43 | The month query returned 23 resources. The year query returned 256. Each area starts with 2,500 entries. These timings do not describe a single 50,000-entry collection. All twenty areas and Reminders were counted. The 100-href multiget limitation is filed as [#500](https://git.kayg.org/kayg/calternal/issues/500). The runner keeps 207 as the expected result and records this 413 as a failed case. It can then continue the independent sync and client checks. The new regression proves that this 413 has no passing timing row. No existing expectation was changed. ## Remaining case states | Requested case | State in this resumed round | | --- | --- | | 50k Log entries, 5k VTODOs, twenty areas | Verified: 55,000 resources from real DAV listings. | | Depth-1 PROPFIND and month/year query | Measured: twenty samples per case in the table above. | | Apple principal and Home discovery | Measured and checked against the expected links. | | One-href multiget | Measured; ETag and VEVENT checked. | | 100-href multiget | Failed: expected 207, actual 413. Filed #500. | | Initial and unchanged sync | Pending on the supplied release; the run stopped before these cases. | | Incremental sync after 1, 100 and 10k changes | Harness present; live full-scale checks pending. | | Fifty polling clients and five writers | Harness present; live full-scale checks pending. | | Area moves and persisted conditional winner | Harness present; live checks pending on the supplied release. | | Real Apple and DAVx5 clients | Not verified. | | Hostile ICS/RRULE and DoS storms | Not run or implemented. | | Webcal and CardDAV | Webcal release pending; CardDAV absent from the supplied source. | | WebDAV | Follow #476 and #429; no duplicate measurement. | No crash, 5xx, data loss or sync collision was established in this round. The missing cases prevent a full stress-coverage claim. The read timings cannot establish that write and sync behavior is correct. ## Validation and cleanup No Rust, API or UI source was changed by this job. Per-crate Clippy/tests and web gates are not applicable to these Python and documentation changes. No build ran. The required fetch and merge from origin/dev ran once, without conflicts. Its source was `5474493b170f5d12b3d0fc9ccf5c3880e3d24bae`. The measured binary is still the supplied 0dc772c36 build. Gate summary output, verbatim: ```text cargo fmt --check exit=0 ---------------------------------------------------------------------- Ran 13 tests in 5.385s OK python scale tests exit=0 bash -n tests/adversarial/run.sh exit=0 git diff --check exit=0 Removed 1 file, 356B total cargo clean exit=0 ``` The Python command was `python3 -m unittest discover -s tests/perf -p 'test_*scale.py' -v`, with TMPDIR in the worktree and bytecode writes off. The added regressions check sync tombstones, failed property deltas, a missing accepted-move delta and preservation of the failed 413 measurement. No existing test expectation changed. Doc comments in both changed Python files were read again before this report. Local Cargo output and web build output were cleaned. The prepared shared release and the VM copies remain available. The copied VM runner includes the #500 classification and the 120-second request limit. When the lock is available, the remaining normal-load command is: ```sh # Run on the perf VM after connecting with netbird ssh. cd /root/caldav-stress-457 flock /root/perf.lock sh -c ' cat /proc/loadavg export TMPDIR="$PWD/target/tmp" python3 tests/perf/caldav_scale.py --server ./calternal-server \ --data-root ./target/tmp --json ./fullscale-core.json \ --commit 0dc772c3697ea9bd01822c26440c32206d472715 \ --changes --poll-seconds 60 --request-timeout 120 ' ``` The known #500 case remains failed. A completed core run with that finding uses `completed-with-findings`, with `core_checks_status: passed`; it does not label the 100-href case as passed.
Author
Owner

Starting CalDAV stress round 3 on job/caldav-stress at c7525cde06b0b72b1f53caab0fe30e1e45d65a8f; shared ancestor: 5474493b170f5d12b3d0fc9ccf5c3880e3d24bae. I am fetching and merging the requested origin/dev (cc25c441b7a974185622a1dee853cf38686d2b67) before the release build and live scenarios.

Starting CalDAV stress round 3 on `job/caldav-stress` at `c7525cde06b0b72b1f53caab0fe30e1e45d65a8f`; shared ancestor: `5474493b170f5d12b3d0fc9ccf5c3880e3d24bae`. I am fetching and merging the requested `origin/dev` (`cc25c441b7a974185622a1dee853cf38686d2b67`) before the release build and live scenarios.
Author
Owner

Round 3 harness is committed as 8177cc8c2 on job/caldav-stress. The source-matched release server was built from cc25c441b7a974185622a1dee853cf38686d2b67; binary SHA-256: 2f3567d91c34839851247bc0acbc25a56aaacd14dca269b8f0342ddf83447ed9.

Local checks: CalDAV harness Ran 13 tests in 3.531s / OK; DAV adversarial probe Ran 11 tests in 0.123s / OK; cargo fmt --check exited 0; Python AST parsing and git diff --check exited 0. No Rust crate source changed. The perf VM's own shared release directory is separate and #549 still has its emulated-disk server active. I will run round 3 from the isolated #457 directory on normal storage, under /root/perf.lock.

Round 3 harness is committed as `8177cc8c2` on `job/caldav-stress`. The source-matched release server was built from `cc25c441b7a974185622a1dee853cf38686d2b67`; binary SHA-256: `2f3567d91c34839851247bc0acbc25a56aaacd14dca269b8f0342ddf83447ed9`. Local checks: CalDAV harness `Ran 13 tests in 3.531s / OK`; DAV adversarial probe `Ran 11 tests in 0.123s / OK`; `cargo fmt --check` exited 0; Python AST parsing and `git diff --check` exited 0. No Rust crate source changed. The perf VM's own shared release directory is separate and #549 still has its emulated-disk server active. I will run round 3 from the isolated #457 directory on normal storage, under `/root/perf.lock`.
Author
Owner

First locked round-3 attempt used normal storage and load average 1.53 2.25 2.18. The 50k/5k seeded Instance became ready after 262.305s. It then hit the harness's 120-second request timeout during fixture projection, before any timing row was collected. The server did not exit; the runner stopped it and marked the JSON incomplete. No crash, 5xx, write loss or sync divergence was observed. I preserved the evidence as /root/caldav-stress-457/round3-normal.json and committed safe per-collection phase labels in bf9838a1b before one bounded retry.

First locked round-3 attempt used normal storage and load average `1.53 2.25 2.18`. The 50k/5k seeded Instance became ready after `262.305s`. It then hit the harness's 120-second request timeout during fixture projection, before any timing row was collected. The server did not exit; the runner stopped it and marked the JSON `incomplete`. No crash, 5xx, write loss or sync divergence was observed. I preserved the evidence as `/root/caldav-stress-457/round3-normal.json` and committed safe per-collection phase labels in `bf9838a1b` before one bounded retry.
Author
Owner

Round 3 finding: the normal-disk perf VM run used binary cc25c441b7 (SHA-256 2f3567d91c34839851247bc0acbc25a56aaacd14dca269b8f0342ddf83447ed9), load at lock start 0.27 1.05 1.56. The 1,000-entry/100-task profile projected all 1,100 resources and completed its initial latency samples, then the new Apple replay check stopped on HTTP 204 from an If-Match replacement because the runner expected 201. The server did not return an error; this is a benchmark expectation bug, and the replay had not yet reached readback. Updated the runner to expect 204 and added a test that confirms the edited body is read back. Perf unit suite: Ran 14 tests in 1.508s / OK. The separate 50,000-entry profile timed out in fixture projection at its 120-second request bound, so it has no valid latency rows. I am retrying the small live profile after copying the runner update.

Round 3 finding: the normal-disk perf VM run used binary cc25c441b7a974185622a1dee853cf38686d2b67 (SHA-256 2f3567d91c34839851247bc0acbc25a56aaacd14dca269b8f0342ddf83447ed9), load at lock start 0.27 1.05 1.56. The 1,000-entry/100-task profile projected all 1,100 resources and completed its initial latency samples, then the new Apple replay check stopped on HTTP 204 from an If-Match replacement because the runner expected 201. The server did not return an error; this is a benchmark expectation bug, and the replay had not yet reached readback. Updated the runner to expect 204 and added a test that confirms the edited body is read back. Perf unit suite: Ran 14 tests in 1.508s / OK. The separate 50,000-entry profile timed out in fixture projection at its 120-second request bound, so it has no valid latency rows. I am retrying the small live profile after copying the runner update.
Author
Owner

Round 3 subscription finding: normal-disk perf VM, runner SHA-256 6546ffe635b8c26e7a6445f5438d8001ae1964207e332030298ef974ee2306c5, lock-start load 0.29 0.87 1.31. Four local subscription creates returned 201, but four concurrent forced refreshes returned HTTP 400. The run stopped before subscription Calendar-view checks and before the later hostile, incremental-change and polling phases. No 5xx or server exit was observed. The benchmark had intentionally omitted response bodies; it now reports only an exact allowlist of the plugin's static safe error messages, with a test that arbitrary messages are omitted. I am rerunning a smaller complete profile to identify whether the rejection comes from the test feed or the route.

Round 3 subscription finding: normal-disk perf VM, runner SHA-256 6546ffe635b8c26e7a6445f5438d8001ae1964207e332030298ef974ee2306c5, lock-start load 0.29 0.87 1.31. Four local subscription creates returned 201, but four concurrent forced refreshes returned HTTP 400. The run stopped before subscription Calendar-view checks and before the later hostile, incremental-change and polling phases. No 5xx or server exit was observed. The benchmark had intentionally omitted response bodies; it now reports only an exact allowlist of the plugin's static safe error messages, with a test that arbitrary messages are omitted. I am rerunning a smaller complete profile to identify whether the rejection comes from the test feed or the route.
Author
Owner

Round 3 reproduced the subscription 304 defect with the perf runner. Each local feed create returned 201 and stored an ETag. A forced refresh sent If-None-Match; the local publisher returned 304, and all four refresh routes returned HTTP 400 with the plugin's fixed safe message “invalid subscription URL”. Source trace: fetch_calendar_inner checks status.is_redirection() before checking NOT_MODIFIED, so it treats 304 as a redirect and fails because the response has no Location header. No 5xx or crash occurred. Fixing this changes the calendar plugin crate, outside this stress job's owned harness files, so I am preserving the live reproducer and continuing the other round-three scenarios.

Round 3 reproduced the subscription 304 defect with the perf runner. Each local feed create returned 201 and stored an ETag. A forced refresh sent If-None-Match; the local publisher returned 304, and all four refresh routes returned HTTP 400 with the plugin's fixed safe message “invalid subscription URL”. Source trace: `fetch_calendar_inner` checks `status.is_redirection()` before checking `NOT_MODIFIED`, so it treats 304 as a redirect and fails because the response has no Location header. No 5xx or crash occurred. Fixing this changes the calendar plugin crate, outside this stress job's owned harness files, so I am preserving the live reproducer and continuing the other round-three scenarios.
Author
Owner

Round 3 complete. Branch: job/caldav-stress. Merged origin/dev at cc25c441b7a974185622a1dee853cf38686d2b67. Head: 129afe87d7eb668a05b5104483575e4f68c68ccd. No push, deploy or merge was made.

Built the CalDAV performance runner, its evidence tests, the adversarial DAV additions, and the round-three result report. The exact cc25 server binary hash was 2f3567d91c34839851247bc0acbc25a56aaacd14dca269b8f0342ddf83447ed9. The VM used normal storage because #549 was still active. The full JSON results are committed in docs/perf/runs/.

Valid 1,000-entry / 100-Task measurements (p50 / p95 / p99):

  • Incremental sync after 1 change: 40.728 / 14,288.164 / 15,171.276 ms; peak RSS 335,073,280 bytes, peak CPU 151.75%.
  • After 100 changes: 42.087 / 106.816 / 14,827.354 ms; peak RSS 335,302,656 bytes, peak CPU 159.81%.
  • After 10,000 changes: 193.409 / 34,554.101 / 76,881.905 ms; all 10,000 changed hrefs and ETags matched a full listing; peak RSS 526,819,328 bytes, peak CPU 199.45%.
  • Apple macOS Calendar and Reminders fixture replay: 69.820 / 14,565.764 / 21,597.541 ms across 24 requests. Six creates and conditional edits passed persisted GET checks.
  • Four changed-feed refreshes: 17.957 / 56.656 / 56.656 ms. Fifty concurrent Calendar range reads: 585.625 / 668.892 / 670.816 ms; all 1,000 Events and four changed titles appeared.
  • Fifty-client convergence: 27,800.625 / 27,879.985 / 27,911.424 ms. All href-to-ETag maps and sampled Event body hashes matched.
  • Fifty-client polling and five live area moves: 130 sync polls at 16,366.154 / 21,594.525 / 22,499.124 ms; five moves at 289,136.036 / 303,397.982 / 303,397.982 ms. All 50 sync caches matched full listings. The phase took 339.719 seconds; peak RSS was 329,404,416 bytes and peak CPU was 362.31%.

The hostile round returned the expected 4xx for malformed and oversized PROPFIND, REPORT and PUT bodies, and 403 for Depth infinity. Eight partial PUTs created no resource while ten PROPFIND requests completed (p95 166.833 ms). The If-Match race had one persisted winner and seven 412 responses. No 5xx, crash, accepted-write loss or ETag/data divergence appeared in the completed checks.

Finding: an unchanged subscription refresh sent its stored ETag; the local publisher returned 304, and the Calendar plugin returned HTTP 400 invalid subscription URL. fetch_calendar_inner checks generic 3xx redirects before 304, then treats the response without Location as an invalid URL. This requires a Calendar plugin behavior change, so this stress job records the live repro and does not change that crate. The successful load phase changed the local feeds, then verified concurrent refresh and Calendar range results. The subscription check used local HTTP; it did not exercise literal webcal:// over live HTTPS.

Gaps: the 50,000-entry / 5,000-Task fixture timed out during fixture listing at the 120-second request bound on two attempts, so it has no latency rows. The combined 10,000-change plus polling/move run timed out in its polling phase; the separate 1,000-entry polling/convergence run completed. #549 was active, so the HDD-emulation run was skipped. The repository has macOS wire fixtures under crates/calternal-dav/tests/fixtures/macos27, but no tests/apple directory or live Apple installation.

Gate output:

  • cargo fmt --check: exit 0, stdout empty.
  • PYTHONPATH=tests/perf python3 -m unittest discover -s tests/perf -p 'test_caldav_scale.py':
.................
----------------------------------------------------------------------
Ran 17 tests in 2.655s

OK
  • python3 -m unittest discover -s tests/adversarial -p 'test_dav_probe.py':
...........
KNOWN litmus owner_modify: 403 Forbidden
KNOWN litmus complex_cond_put: 400 Bad Request
----------------------------------------------------------------------
Ran 11 tests in 0.171s

OK
  • git diff --check: exit 0, stdout empty.
  • cargo clean:
     Removed 1 file, 356B total
  • No Rust crate source or web source changed, so per-crate Rust clippy/test and web check/test were not run. bun run build succeeded earlier (✓ built in 40.41s); its generated web output was removed.

Decisions for owner: use the allowlisted local HTTP feed for subscription load while preserving the 304 failure as a finding; use the 1,000-entry fixture for completed concurrent convergence after the 10,000-change combined polling phase timed out; report the macOS fixtures as protocol replay rather than a live client test.

Round 3 complete. Branch: `job/caldav-stress`. Merged `origin/dev` at `cc25c441b7a974185622a1dee853cf38686d2b67`. Head: `129afe87d7eb668a05b5104483575e4f68c68ccd`. No push, deploy or merge was made. Built the CalDAV performance runner, its evidence tests, the adversarial DAV additions, and the round-three result report. The exact cc25 server binary hash was `2f3567d91c34839851247bc0acbc25a56aaacd14dca269b8f0342ddf83447ed9`. The VM used normal storage because #549 was still active. The full JSON results are committed in `docs/perf/runs/`. Valid 1,000-entry / 100-Task measurements (p50 / p95 / p99): - Incremental sync after 1 change: 40.728 / 14,288.164 / 15,171.276 ms; peak RSS 335,073,280 bytes, peak CPU 151.75%. - After 100 changes: 42.087 / 106.816 / 14,827.354 ms; peak RSS 335,302,656 bytes, peak CPU 159.81%. - After 10,000 changes: 193.409 / 34,554.101 / 76,881.905 ms; all 10,000 changed hrefs and ETags matched a full listing; peak RSS 526,819,328 bytes, peak CPU 199.45%. - Apple macOS Calendar and Reminders fixture replay: 69.820 / 14,565.764 / 21,597.541 ms across 24 requests. Six creates and conditional edits passed persisted GET checks. - Four changed-feed refreshes: 17.957 / 56.656 / 56.656 ms. Fifty concurrent Calendar range reads: 585.625 / 668.892 / 670.816 ms; all 1,000 Events and four changed titles appeared. - Fifty-client convergence: 27,800.625 / 27,879.985 / 27,911.424 ms. All href-to-ETag maps and sampled Event body hashes matched. - Fifty-client polling and five live area moves: 130 sync polls at 16,366.154 / 21,594.525 / 22,499.124 ms; five moves at 289,136.036 / 303,397.982 / 303,397.982 ms. All 50 sync caches matched full listings. The phase took 339.719 seconds; peak RSS was 329,404,416 bytes and peak CPU was 362.31%. The hostile round returned the expected 4xx for malformed and oversized PROPFIND, REPORT and PUT bodies, and 403 for Depth infinity. Eight partial PUTs created no resource while ten PROPFIND requests completed (p95 166.833 ms). The If-Match race had one persisted winner and seven 412 responses. No 5xx, crash, accepted-write loss or ETag/data divergence appeared in the completed checks. Finding: an unchanged subscription refresh sent its stored ETag; the local publisher returned 304, and the Calendar plugin returned HTTP 400 `invalid subscription URL`. `fetch_calendar_inner` checks generic 3xx redirects before 304, then treats the response without Location as an invalid URL. This requires a Calendar plugin behavior change, so this stress job records the live repro and does not change that crate. The successful load phase changed the local feeds, then verified concurrent refresh and Calendar range results. The subscription check used local HTTP; it did not exercise literal `webcal://` over live HTTPS. Gaps: the 50,000-entry / 5,000-Task fixture timed out during fixture listing at the 120-second request bound on two attempts, so it has no latency rows. The combined 10,000-change plus polling/move run timed out in its polling phase; the separate 1,000-entry polling/convergence run completed. #549 was active, so the HDD-emulation run was skipped. The repository has macOS wire fixtures under `crates/calternal-dav/tests/fixtures/macos27`, but no `tests/apple` directory or live Apple installation. Gate output: - `cargo fmt --check`: exit 0, stdout empty. - `PYTHONPATH=tests/perf python3 -m unittest discover -s tests/perf -p 'test_caldav_scale.py'`: ``` ................. ---------------------------------------------------------------------- Ran 17 tests in 2.655s OK ``` - `python3 -m unittest discover -s tests/adversarial -p 'test_dav_probe.py'`: ``` ........... KNOWN litmus owner_modify: 403 Forbidden KNOWN litmus complex_cond_put: 400 Bad Request ---------------------------------------------------------------------- Ran 11 tests in 0.171s OK ``` - `git diff --check`: exit 0, stdout empty. - `cargo clean`: ``` Removed 1 file, 356B total ``` - No Rust crate source or web source changed, so per-crate Rust clippy/test and web check/test were not run. `bun run build` succeeded earlier (`✓ built in 40.41s`); its generated web output was removed. Decisions for owner: use the allowlisted local HTTP feed for subscription load while preserving the 304 failure as a finding; use the 1,000-entry fixture for completed concurrent convergence after the 10,000-change combined polling phase timed out; report the macOS fixtures as protocol replay rather than a live client test.
Author
Owner

Owner decision (2026-10-01): in-memory locks and per-User write serialisation are accepted, but the owner asked for the performance cost to be improved: parallel Finder uploads must not be slowed by the serialisation. Covered by #476 (WebDAV lock benchmark): measure parallel uploads, then narrow the lock to the paths involved (per-resource lock tokens) so independent uploads run in parallel.

**Owner decision (2026-10-01):** in-memory locks and per-User write serialisation are accepted, but the owner asked for the performance cost to be improved: parallel Finder uploads must not be slowed by the serialisation. Covered by #476 (WebDAV lock benchmark): measure parallel uploads, then narrow the lock to the paths involved (per-resource lock tokens) so independent uploads run in parallel.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal#457
No description provided.