DAV: shared scoped transport with CardDAV mounted in the server #794
Open
kayg
wants to merge 9 commits from
feat/dav-transport into issue/carddav-read-perf-fix-r2
pull from: feat/dav-transport
merge into: kayg:issue/carddav-read-perf-fix-r2
kayg:main
kayg:fix/shared-row-swipes
kayg:feat/pass8
kayg:t3/paged-search-reconcile-final
kayg:feat/style-sheet-fixes
kayg:storage/wal-checkpoint-off-save-1051
kayg:feat/contrast
kayg:review/calendar-2
kayg:dev
kayg:feat/collections-db
kayg:fix/instant-keys-1056
kayg:feat/money-round
kayg:perf/stalls-1054
kayg:wip/tiering-v3-cold4
kayg:wip/tiering-v3-cold5
kayg:port/rows-actions
kayg:port/rows-drop
kayg:port/hidden-blocks
kayg:port/rows
kayg:port/port-tables
kayg:port/port-tables-2
kayg:t3/mail-1011-liveness
kayg:port/devices
kayg:port/port-attachments
kayg:port/port-attachments-2
kayg:port/port-attachments-3
kayg:docs/design-consistency
kayg:docs/engineering-standards
kayg:fix/rusqlite-0.41-rustsec-2026-0459
kayg:feat/iphone-fixes
kayg:shared/restore-and-stale-918-919
kayg:fix/phone-top-band-contrast
kayg:feat/notes-approve
kayg:perf/soak-max-gate
kayg:feat/files-s1-identity
kayg:fix/lifecycle-event-id
kayg:feat/quickfix
kayg:wip/tiering-v3-cold
kayg:perf/web-mockup-frame-fixes
kayg:port/contacts-merge
kayg:port/contacts-edit
kayg:test/shared-room-no-deleted-text
kayg:perf/first-paint-credits
kayg:fix/shared-history-after-grant
kayg:fix/phone-swipe-regressions
kayg:feat/contrast-r1
kayg:review/sharing-pr3-review
kayg:feat/tiering-v3-s2-tags
kayg:feat/folder-drop
kayg:fix/deskpills-lazy-share
kayg:feat/sharing-s1-pr3
kayg:tmp/money-round-before
kayg:fix/phone-pane-backdrop-roots
kayg:fix/palette-preload-chips
kayg:fix/invite-defaults
kayg:port/tasks-matrix
kayg:fix/restore-green-gates
kayg:fix/sharing-fast-path-hardening
kayg:t3/photos-s1
kayg:feat/tiering-v3-s1-namespace
kayg:notes-archive-hide
kayg:feat/tasks-actions
kayg:t3/photos-plan-slice-one
kayg:feat/whiteboard-s1
kayg:t3/paged-search-reconcile
kayg:t3/smooth-pane-transitions
kayg:t3/index-position-startup-scan
kayg:fix/private-staging-759b-r2
kayg:feat/imap-notes-fetch
kayg:feat/imap-notes-projection
kayg:feat/imap-notes-readonly
kayg:feat/imap-notes-auth
kayg:feat/imap-notes-server-foundation
kayg:docs/undo-block-ids-plan
kayg:fix/undo-768
kayg:proto/block-identity-v7d
kayg:issue/carddav-read-perf-fix-r2
kayg:issue/carddav-read-r2
kayg:docs/imap-766-plan-v2
kayg:docs/imap-notes-plan
kayg:docs/quota-plan-2
kayg:fix/parallel-test-flakes
kayg:feat/contacts-companion-pure
kayg:docs/calendar-backend-v2-plan
kayg:feat/calendar-ical-converter
kayg:docs/tasks-writes-v2-plan
kayg:docs/carddav-writes-v2-plan
kayg:docs/contacts-import-v2-plan
kayg:issue/610-pm-midnight
kayg:feat/calendar-v2-s1-containment
kayg:docs/dav-recorder-v2-plan
kayg:plan/previews-865
kayg:plan/save-log-durable-entry
kayg:fix/e2e-data-on-ram
kayg:feat/appwindow3
kayg:feat/appwindow2
kayg:feat/appwindow
kayg:feat/money-p1
kayg:feat/keys-sheet
kayg:review/calendar-2-themes
kayg:feat/smooth-cursor
kayg:fix/float-style
kayg:review/calendar-2-float
kayg:release/2026-11-06-hotfix
kayg:archive/port/rows-drop-code
kayg:archive/port/rows-actions
kayg:archive/port/rows
kayg:scratch/tasks-894-ui-gates
kayg:review/calendar-2-night-wip
kayg:release/2026-11-05
kayg:archive/feat/tiering-v3-s1-namespace
kayg:archive/flaky/rows-drop-fixed
kayg:archive/flaky/rows-actions
kayg:archive/feat/tiering-v3-reader
kayg:archive/feat/tiering-v3-roots
kayg:archive/flaky/rows
kayg:sim/bm15-final
kayg:sim/bm15-fix
kayg:sim/bm15-bis-932
kayg:sim/bm15-bis-909
kayg:sim/bm15
kayg:sim/bm15-bis-887
kayg:perf/tiering-option-b
kayg:port/style-3
kayg:port/style-2
kayg:port/style
kayg:fix/sw-lazy-precache
kayg:fix/vim-w-waits-for-save
kayg:fix/signout-test-races
kayg:fp-scratch/all
kayg:sim/bm15-first-paint
kayg:archive/bm15/rows-drop
kayg:archive/bm15/rows-actions
kayg:fix/palette-snippet-contrast
kayg:archive/bm15/rows
kayg:archive/bm15/hidden
kayg:archive/plan/save-log-durable-entry
kayg:mock/money-fix2
kayg:archive/fix/e2e-data-on-ram
kayg:mock/appearance-all
kayg:mock/pill-press
kayg:archive/docs/design-consistency
kayg:mock/auto-swipes
kayg:mock/mail-actions
kayg:archive/feat/mail-p1
kayg:mock/money-static
kayg:archive/review/standards-917
kayg:archive/docs/engineering-standards
kayg:perf/tiering-761-fix
kayg:mock/type-audit
kayg:mock/third-pane
kayg:feat/contacts-import-v2-s1
kayg:perf/executor-hot-path
kayg:archive/port/hidden-blocks
kayg:archive/port/devices
kayg:scratch/executor-on-894
kayg:scratch/executor-spans2
kayg:scratch/executor-spans
kayg:train/2026-11-03-bm14c
kayg:archive/port/rows-drop
kayg:feat/tiering-761-d-scale
kayg:feat/tiering-761-c-index
kayg:feat/tiering-761-b-reader
kayg:archive/review/sharing-pr3-review-9fec3d1f
kayg:train/2026-11-03-bm14b
kayg:perf/ports-lazy-budgets
kayg:feat/tiering-761-a-migration
kayg:train/2026-11-03-bm14
kayg:train/2026-11-03-bm12
kayg:archive/review/sharing-pr3-review
kayg:archive/feat/sharing-s1-pr3
kayg:train/2026-11-03-bm11
kayg:archive/feat/imap-notes-fetch
kayg:train/2026-11-03-bm10
kayg:archive/review/sharing-pr3-review-code
kayg:archive/plan/previews-865
kayg:train/2026-11-02-bm9
kayg:archive/port/port-attachments-3
kayg:archive/port/contacts-merge
kayg:fix/motion-audit-859
kayg:train/2026-11-02-bm8
kayg:archive/scratch/bm8-prep
kayg:archive/port/port-pickers
kayg:archive/port/port-tables-2
kayg:archive/port/port-tables
kayg:archive/feat/sharing-s1-pr3-code
kayg:archive/scratch/bm7-fixed
kayg:train/2026-11-02-bm7
kayg:archive/fix/parallel-test-flakes-code-minipc01
kayg:train/2026-11-02-bm6
kayg:docs/imap-766-readonly-slice
kayg:feat/dav-recorder-v3
kayg:research/788-diagnosis
kayg:archive/fix/parallel-test-flakes
kayg:archive/perf/pr792-cold-index-edit
kayg:docs/sharing-slice-1
kayg:archive/docs/imap-766-plan-v2
kayg:feat/dav-recorder-v2
kayg:archive/docs/dav-recorder-v2-plan
kayg:spike/imap-766-s0-cases
kayg:archive/fix/undo-768
kayg:feat/dav-recorder
kayg:archive/docs/contacts-import-v2-plan
kayg:archive/feat/calendar-ical-converter
kayg:feat/contacts-import
kayg:perf/cold-growth-on-764
kayg:perf/cold-growth-on-tiering
kayg:archive/docs/tasks-writes-v2-plan
kayg:archive/docs/calendar-backend-v2-plan
kayg:archive/feat/contacts-companion-pure
kayg:feat/tasks-set-status
kayg:feat/tasks-move-reorder
kayg:archive/docs/carddav-writes-v2-plan
kayg:archive/feat/calendar-v2-s1-containment
kayg:feat/tasks-delete-promote-duplicate
kayg:archive/feat/dav-transport
kayg:archive/fix/carddav-rebuild-r1
kayg:archive/fix/carddav-retention-r1
kayg:feat/carddav-writes
kayg:perf/quota-on-tiering
kayg:perf/quota-simple
kayg:perf/cold-growth-on-quota-stack
kayg:feat/calendar-identity
kayg:feat/calendar-event-parser
kayg:feat/calendar-props-maps
kayg:port/glass-when-ring
kayg:feat/tiering-761-s1
kayg:wip/10by32-01-impl-759b-scratch-20261030
kayg:wip/6by32-01-bm3-webkit-pause-20261030
kayg:wip/10by32-01-bm3-chromium-pause-20261030
kayg:wip/6by32-01-tier-761-s1-pause-20261030
kayg:spike/imap-766-s0
kayg:wip/6by32-02-calternal-pause-20261030
kayg:wip/8by64-01-review-688-pause-20261030
kayg:wip/6by32-01-verify-744-pause-20261030
kayg:wip/6by32-01-verify-742-pause-20261030
kayg:fix/private-staging-759b
kayg:wip/6by32-01-review-748-pause-20261030
kayg:wip/6by32-01-review-733c-pause-20261030
kayg:wip/6by32-01-review-733b-pause-20261030
kayg:wip/6by32-01-perf-idle-8-pause-20261030
kayg:wip/6by32-01-perf767-base-pause-20261030
kayg:wip/6by32-01-perf767b-767-pause-20261030
kayg:wip/6by32-01-perf767b-764-pause-20261030
kayg:wip/6by32-01-perf767-767-pause-20261030
kayg:wip/6by32-01-perf767-764-pause-20261030
kayg:wip/6by32-01-lists-b-pause-20261030
kayg:wip/6by32-01-ids-verify5-pause-20261030
kayg:wip/6by32-01-ids-verify4-pause-20261030
kayg:review/calendar-month
kayg:wip/10by32-02-undo-768-20261030
kayg:test/ids-verify3
kayg:wip/10by32-02-bm3-chromium-20261030
kayg:wip/10by32-01-review-753-20261030
kayg:wip/10by32-01-perf-idle-2-20261030
kayg:wip/10by32-01-bm2-webkit2-20261030
kayg:plan/759b-staging
kayg:train/2026-10-30-bm2
kayg:review/758b-tests
kayg:review/758-tests
kayg:review/764d-tests
kayg:review/767b-tests
kayg:review/preview-2026-10-29
kayg:review/767-tests
kayg:docs/tiering-731-plan
kayg:wip/c6b02-when2
kayg:wip/c6b02-tasks-create-fix5
kayg:wip/c6b02-settings-frost-mock
kayg:wip/c6b02-settings-frost-base
kayg:wip/c6b02-settings-frost
kayg:wip/c6b02-ring
kayg:wip/c6b02-review-733d
kayg:wip/c6b02-bm1-full-a
kayg:wip/compute02-when-field
kayg:wip/compute02-webkit-lists-repro
kayg:wip/compute02-train-bl2-dev
kayg:wip/compute02-dev-green-pw164
kayg:docs/deploy-plan
kayg:review/764c-tests
kayg:review/764b-tests
kayg:review/748g-tests
kayg:review/764-tests
kayg:review/759b-tests
kayg:fix/storage-owner-liveness-642
kayg:fix/storage-fix-7
kayg:wip/compute02-storage-fix-7
kayg:review/759-tests
kayg:feat/tiering-731
kayg:wip/tiering-731-first-attempt
kayg:wip/compute02-storage-fix-1
kayg:review/754g-tests
kayg:perf/idle-honest-2
kayg:review/754f-tests
kayg:review/754e-tests
kayg:review/755-tests
kayg:review/754d-tests
kayg:review/754c-tests
kayg:review/754b-tests
kayg:review/754-tests
kayg:fix/storage-private-tmp-642-dev
kayg:wip/compute02-verify-750
kayg:test/ids-verify5
kayg:test/ids-verify4
kayg:fix/storage-exact-file-quarantine-642
kayg:wip/compute02-verify-740
kayg:perf/one-flush-save
kayg:review/calendar-static
kayg:wip/compute02-verify-737
kayg:review/indexing-ring
kayg:review/when-field-2
kayg:wip/compute02-review-733
kayg:proto/block-identity-2-review
kayg:proto/block-identity-review
kayg:wip/c6b02-tc-design
kayg:review/when-field
kayg:issue/tasks-create-ids
kayg:issue/tasks-create
kayg:review/combined
kayg:wip/compute02-review-combined
kayg:review/task-polish
kayg:review/top-buttons
kayg:review/q1-q5
kayg:train/2026-10-26-bl2
kayg:archive/wt-398h
kayg:archive/train-bm-proptest-seed
kayg:archive/integ325-293
kayg:archive/integ325-ci
kayg:archive/client-auth-review-baseline
kayg:archive/wt-sim-4853
kayg:archive/wt-sim-4811
kayg:archive/wt-448m
kayg:archive/wt-398a-allocator
kayg:issue/calendar-adr
kayg:archive/old/train/2026-10-23bk2
kayg:archive/old/train/2026-10-23bk
kayg:issue/469-mockup-9a
kayg:issue/smart-tasks-mockup
kayg:issue/469-menus
kayg:issue/652-signout-flake
kayg:issue/652-history-fix7
kayg:issue/652-history-fix6
kayg:archive/old/issue/spring-check-perf
kayg:issue/spring-check-perf
kayg:issue/659-rename-fast
kayg:archive/old/train/2026-10-21ar
kayg:issue/search-hardening-3
kayg:issue/652-history-fix5
kayg:issue/660-port-sheets-glass
kayg:issue/652-history-fix4
kayg:issue/652-history-fix3
kayg:issue/652-history-fix2
kayg:issue/652-history-flake
kayg:train/2026-10-21an
kayg:issue/settings-admin-port
kayg:issue/search-port
kayg:train/2026-10-20am
kayg:issue/storage-split-fix2
kayg:issue/storage-split
kayg:archive/old/issue/folder-ids-fix
kayg:train/2026-10-20al
kayg:archive/old/issue/folder-ids
kayg:train/2026-10-20ak
kayg:issue/tables-mockup
kayg:train/2026-10-19aj
kayg:train/2026-10-19ai
kayg:issue/469-merge-fixes
kayg:issue/sidebar-band
kayg:archive/old/issue/608-settings-spec
kayg:train/2026-10-19ah
kayg:issue/swipe-offscreen
kayg:train/2026-10-19ag
kayg:archive/old/issue/590-nlp-adr
kayg:archive/old/issue/587-event-after-write-2
kayg:train/2026-10-19af
kayg:archive/old/issue/587-event-after-write
kayg:issue/469-pill-room-c
kayg:issue/469-pill-room
kayg:train/2026-10-19ae
kayg:issue/469-narrow-handle
kayg:issue/397-ios-swipe-2
kayg:archive/old/issue/adrs-photos-files-tasks
kayg:issue/469-desk-fixes
kayg:archive/old/issue/auto-update-adr
kayg:issue/469-filter-gap
kayg:issue/469-port-1b
kayg:issue/442-opacity-flake
kayg:archive/397-ios-swipe-2
kayg:issue/327-web-fast-3
kayg:archive/old/issue/469-port-1
kayg:issue/469-port-1
kayg:issue/327-web-fast-2
kayg:archive/old/issue/327-web-fast
kayg:archive/old/issue/425-stt-bench-vq1
kayg:archive/old/issue/445-no-bleed
kayg:archive/old/issue/400-swipe-mockup-2
kayg:issue/426-client-review
kayg:issue/426-client-2
kayg:issue/426-client
kayg:archive/old/issue/476-safe-area-lab
kayg:archive/445-top-light-2
kayg:archive/old/issue/445-top-light
kayg:issue/471-blocks-mockup
kayg:archive/old/issue/448-links-app-2
kayg:archive/old/issue/448-links-app
kayg:archive/old/issue/398-cold-links
kayg:issue/434-442-small-2
kayg:issue/434-442-small
kayg:archive/old/issue/398-unload
kayg:archive/old/issue/445-bottom-band
kayg:issue/445-bottom-band
kayg:issue/351-rem-3
kayg:archive/312-views-mockup
kayg:issue/351-rem-2
kayg:issue/351-rem
kayg:archive/old/issue/327-first-note
kayg:issue/395-width-phone
kayg:archive/old/issue/327-typing
kayg:issue/396-ios-edges
kayg:issue/397-ios-swipe
kayg:archive/398-allocator
kayg:archive/old/issue/327-notes-index
kayg:issue/345-347-contrast-empty-2
kayg:archive/old/issue/44-arenas
kayg:issue/44-arenas
kayg:archive/integ325
kayg:archive/old/issue/327-perf-harness
kayg:archive/old/issue/44-thp
kayg:issue/44-thp
kayg:archive/old/issue/285-sticky-pills
kayg:archive/old/issue/44-trim-3
kayg:issue/44-trim-3
kayg:archive/old/issue/165-cards
kayg:archive/old/issue/165-picker-2
kayg:archive/old/issue/212-multi-select
No reviewers
Labels
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
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!794
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/dav-transport"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Stack refresh: cache review round 1 fixes, gates green
Head
80ec1fa3includes updated #7773c8ddf53and #776f3d6361d. Integration status table, exact gates and limits. All requested transport/package, mount, contract, clippy and fmt gates passed before push. Never merged into dev; refreshed-stack independent review remains pending.Round 2 fix, final review pending
Implementation plan and failure table: #794 (comment). Response admission follows owner-backed Bytes through Hyper's socket queue. The DAV listener preserves queued/vectored writes, including a scalar-I/O fallback, instead of allowing Hyper to flatten replies into uncharged buffers. Default budgets: 64 MiB total reply reservations, 8 MiB per request, at most 8 admitted requests under that byte budget, still at most 4 per owner and an upper count ceiling of 64. Reserve before buffering/readiness/allocation, refuse immediately with 429. O(body + reply) work and bounded request/byte state; transient serializer/store buffers remain separately bounded by the existing per-reply limits.
Default 60 s total from handler entry through body read, readiness/handling and response socket writes; 10 s idle between request-body frames and while response writes are pending. Configurable through
calternal_dav::Config. Tower-http supplies handler and body-read timeouts; the DAV-aware listener handles socket write idle and total expiry because body middleware cannot cover already-polled Hyper frames. Expiry closes the connection. Running blocking closures keep admission and byte reservations until they actually end. On HTTP/2, expiry closes the shared connection, so other streams retry too.Round-2 fixes pushed at
9e95ad41a0. Final dev-01 gates: 264 package tests passed, 7 existing ignores; mount, contract, shutdown I/O, clippy -D warnings and fmt passed. Full status table, exact commands and evidence. All 1,198 source files match the tested isolated VM tree. Independent FINAL review round 3 remains pending. Never merged. The original gate record below is historical at9a6c56a8.Plan, bounds, and failure table
Shared DAV transport, with CardDAV as adapter #1, landing after #777 and #782, into
dev. Re-mergedorigin/feat/dav-app-passwordsthrougha59f782ebefore the round-1 fixes. Never merge automatically. Refs #657.The transport owns credential-scoped discovery, raw-path validation, PROPFIND/REPORT/GET/HEAD/OPTIONS, XML, bounded pages and conditional reads. CardDAV owns its journal-fed projection. A CalDAV-shaped adapter proves reuse; actual CalDAV conversion, calendar-query, recurrence and writes remain ADR 0067 steps 7–9.
Hard bounds, enforced before the corresponding allocation/work:
c, the calendar stubcal.Sizes and complexity: XML preflight/tree parsing O(body); selection copies are charged before ownership and unique-property comparisons are bounded by 256 properties; metadata pages O(log n + page), GET O(log n + bytes), multiget O(hrefs × log n + bounded bytes), sync one bounded payload page. Admission scans at most 64 live user buckets and drops dead buckets. Existing O(n) cold projection rebuild staging remains inherited, separate from request XML/reply bounds.
Gates
All passed on dev-01 in the Nix shell through one
~/bin/slot, at the exact source tree committed as9a6c56a86f. Final target directory is isolated:/home/claude/Developer/Worktrees/dav794-r1/target.Package gate: 254 passed, 0 failed, 7 existing ignores (DAV 26, CardDAV 26, auth 179, server 23). Mount and contract: one test each passed. Clippy
-D warningsand fmt clean. Explicit memory rerun also passed:cargo test -j4 -p calternal-dav --test memory_bound --locked -- --nocapture. The hostile 68,680-byte authenticated request measured 12,884 KiB peak RSS, 88 KiB growth, under assertions of 64 MiB absolute and 8 MiB growth, with a bounded 400 reply. Log:~/dav794-r1-verified.log, endingGATES_EXIT=0.Compared SHA-256 for all 1,196 source files between control and tested VM worktrees: identical, excluding VM-only Nix shell files. No Nix files committed. Earlier shared-target baseline/fixed binary reuse was detected; that sample was discarded and the complete final gates rerun in the isolated target directory.
Decisions and open risks
All five round-1 findings are fixed; none deferred. Detailed findings/status and failing-before evidence are in the round-1 implementation comment. Independent review of the new head remains pending; the maximum is three review rounds.
Byte-overflow replies deliberately refuse rather than send partial XML or a misleading sync token; clients must reduce href counts/nresults. Future adapters must choose globally distinct namespace prefixes. Percent escapes and odd/raw path spellings remain fail-closed; URLs never select storage identity. Inherited cache compaction/cold rebuild staging, native Apple replay and perf-VM latency gates remain later work and are not claimed here. This PR remains read-only and unmerged.
Independent review, round 1
Reviewed
26936341e0. Read the common brief, ADRs 0064/0067/0068, this PR's plan/failure table, all five #782 review/status comments, and the transport, CardDAV adapter/projection/cache, authentication changes and server mount. Defensive review of our own code. No production code changed, committed or pushed.Verdict: fix first. P0: 0; P1: 1; P2: 4; P3: 0. One P2 is the still-open prerequisite from #782's final review, explicitly distinguished below.
Findings
R1-1 — P1: byte/node limits do not bound XML selection allocations or response expansion
Location: crates/dav/src/xml.rs:113, also lines 118, 207–215 and 264–280; principal call sites
crates/dav/src/serve.rs:530and:589.A valid app password can submit a PROPFIND with one long inherited namespace and many
<x:a/>properties.selectioncopies the entire resolved namespace into every property, thenrespondechoes that namespace declaration for every unknown property. Both happen on the async worker for principal requests. Neither the 1 MiB input cap, 20,000-node cap nor resource-count cap bounds the resulting allocation usefully.Small VM reproduction against the real router: an 11,336-byte request, 512 properties, an 8,196-byte namespace and Depth 0 produced 4,196,352 bytes of owned namespace strings and a 4,207,909-byte 207 response. No stored contacts are needed. Scaling the same accepted shape to a 512 KiB namespace and 19,000 property nodes stays below both input limits while demanding roughly 9.3 GiB just for namespace copies, before response strings. This is an allocation-derived exhaustion scenario; I deliberately did not run an OOM-sized request. Repeated
address-dataproperties can additionally multiply returned card bytes, beyond the PR's stated one-copy-per-card 250 MiB estimate.Fix: enforce namespace/name length and aggregate selection-allocation budgets before cloning; deduplicate requested qualified properties; impose a checked serialized-byte budget covering every property/resource, including unknown-property echoes and repeated body properties. Return a bounded protocol error on overflow. Keep principal parsing/serialization off async workers as well. Add the inherited-long-namespace and duplicate-address-data attacks below the byte/node caps; assert bounded allocation/output and prompt rejection.
R1-2 — P2: #782's final required cold-auth admission fix is absent at the mounted head
Location: crates/auth/src/app_password.rs:264,
crates/auth/src/lib.rs:133, and the new mount atcrates/calternal/src/app.rs:87.This is the existing #782 R3-1 prerequisite, not a newly discovered auth issue or a fourth auth review. The final review explicitly requires it before mounting. Head
26936341still has only the eight worker permits andtimeout(COLD_WAIT, acquire_owned()); there is no separate pending-admission cap. Arbitrarily many fresh plausible junk credentials can join the 250 ms queue. Source exhaustion changes the post-lookup result rather than admission. This PR exposes that code publicly while claiming the final review fixes were incorporated.Fix: carry the required bounded pending-cold admission budget into the landing dependency/head; acquire it with
try_acquire_ownedbefore the FIFO wait, retain it through the operation and preserve warm-cache bypass. Prove immediate excess rejection and permit release on timeout/cancellation with a blocked DB worker. Existing finite-burst auth tests do not prove a bound on retained pending requests. Retaining the prior P2 severity; no measured OOM claim.R1-3 — P2: the transport's new blocking budget also leaves an unbounded retained-request queue
Location: crates/dav/src/serve.rs:171, with body buffering/copying at lines 144 and 161 and readiness waits at 303–312.
The 32 permits bound running closures, not requests waiting for a permit. Each authenticated request has already buffered up to 1 MiB and can also retain the
body.to_vec()copy while waiting. A slow cache/read, or one user's serialized projection barrier, can retain an arbitrary number of these requests; the blocking-permit wait has no timeout either. Invalid XML/Depth is only parsed after readiness and blocking admission, so rejected work can occupy this queue too. This is separate from the anonymous auth queue in R1-2: a single valid contacts credential reaches it repeatedly.Fix: add a finite request-admission budget before buffering/readiness, with immediate bounded overload responses and cancellation-safe ownership. Keep the existing running-work permit inside the blocking closure. Validate cheap protocol constraints before store initialization where possible. Test more concurrent requests than the admission cap against a held store/barrier, and verify immediate rejection, bounded retained admissions and cancellation release. The current ticker test proves offloading, not admission bounds.
R1-4 — P2: principal discovery silently treats a failed projection as an absent home
Location: crates/dav/src/serve.rs:597.
For authenticated Depth-1 principal discovery,
Ok(Some(h)) if h.ready().await.is_ok()falls through toOk(_) => {}when readiness fails. The reply is a successful 207 with the home silently omitted. The same failure on a direct home request correctly returns 503. An adapterhome()error on discovery instead gets 500, also inconsistent with the direct-home 503 policy. A temporary broken projection therefore looks like a missing collection during discovery, contrary to the failure table's retryable-503 contract.VM fault injection confirmed principal=207, one principal response only; direct home=503. Neither response leaked the injected private error text.
Fix: distinguish
Nonefrom readiness failure; propagate home-open/readiness failures as a bounded 503 response consistently. Add HTTP tests for both failure points on principal Depth 1 and direct-home requests, followed by recovery. The cache recovery test only proves cursor/data retention and does not exercise these HTTP paths.R1-5 — P2: actual CardDAV namespaces collide with the CalDAV stub in shared discovery
Location: crates/dav/src/serve.rs:558,
crates/dav/src/xml.rs:222,crates/carddav/src/adapter.rs:20,crates/dav/tests/common/mod.rs:141and:318.Principal namespace aggregation deduplicates whole
(prefix, URI)pairs. Real CardDAV declarescfor CardDAV, while the calendar stub declarescfor CalDAV. With both mounted and a credential granting both scopes, discovery emits two differentxmlns:cattributes on the same element, making the entire 207 response invalid XML. This is a shared-adapter composition bug; the current production mount has only CardDAV, so its single-adapter discovery does not trigger it.A VM probe using the exact real CardDAV namespace specification alongside the existing calendar stub produced 207 +
DuplicatedNamespace("c", …)from roxmltree. The existing two-adapter test misses this becauseStubCardsdeclaresnamespaces: &[]instead of the real adapter's namespaces.Fix: give adapters globally distinct prefixes and validate conflicts when constructing the router, or scope each adapter's XML declarations locally. Add a coexistence test using the real CardDAV adapter and calendar stub, with dual-scope credentials and namespace-aware parsing of Depth 0/1 discovery.
Failure-table test audit
home(user)receives the credential owner. Tests do not count adapter calls, so the literal “no adapter lookup” claim is supported by code flow rather than a lookup assertion.allow_dtd: falseis the actual XXE protection.read.rsitself only suppliesurn:expired; broader coverage comes from cache tests.No cross-user card read, URL-derived storage identity, adapter-scope widening, unauthenticated user-existence oracle, XXE fetch or internal-error disclosure found in the reviewed paths. Raw-path handling is fail-closed at the actual root mount; percent escapes, dot/empty segments, noncanonical IDs and extra item segments cannot select another user's book. Well-known redirects authenticate first and use credential-owned locations with no-store. Existing deferred D6 writes/CSRF, native Apple replay and perf-VM gates are not re-raised here.
Verification
On calternal-dev-01-compute02, isolated detached worktree
~/Developer/Worktrees/review794-round1at the exact reviewed commit, Nix dev shell, through~/bin/slot,-j4:15 passed: all 11 existing transport integration tests and four temporary reviewer probes. Probe tests intentionally assert the observed buggy behavior; their passing reproduces the findings, not a fixed implementation. A 15,000-level XML nesting probe also completed without stack failure. Log:
~/review794-round1-verify.log; job exited 0. Temporary probes are only in the isolated VM worktree and were not committed/pushed. Also inspected the PR's recorded VM gate log, which ends EXIT=0; did not rerun its full clippy/CardDAV/auth/server train. Local read-onlygit diff --check origin/dev...HEADpassed. No control-host builds/tests/installs.Required: fix R1-1 through R1-5 before landing. P0: none. P1: R1-1, authenticated XML allocation/response amplification can exhaust the shared server.
Round 1 implementation response
Pushed
9a6c56a86fto the same branch. Re-merged the finalized #782 heada59f782efirst. All five findings fixed; no finding waived. Never merged. This is the implementation response to review round 1, not another independent review round.review_round1, real CardDAV repeated-address-data/aggregate-report tests andmemory_boundfail before and pass after.a59f782epending try-acquire before FIFO, warm-cache bypass, timeout/cancellation release. Adapted its test to this branch's scope-list API. The blocked-DB regression passes; in the isolated inverse-patch fixture, removing only pending acquisition makes it fail.c/calbindings plus construction-time conflict validation. Real CardDAV + calendar adapter test parses Depth 0/1 discovery and checks namespace-aware properties. On original26936341it fails with DuplicatedNamespace("c", …).The reviewer's original probes were recovered from
review794-round1on dev-01. Failing-before logs:~/dav794-r1-red.log,~/dav794-r1-red-bounds.log,~/dav794-r1-before.log; auth inverse-patch:~/dav794-r1-auth-red.log; response-body admission:~/dav794-r1-body-red.log. The original-head authenticated HTTP memory probe grew peak RSS by 131,068 KiB; the final test asserts both an absolute 64 MiB peak and less than 8 MiB growth. Final measurement: 12,884 KiB peak, 88 KiB growth, output under 1 KiB, 400 rejection. No OOM-sized input was needed.Final authoritative gates on calternal-dev-01-compute02, Nix shell,
~/bin/slot, isolated target/home/claude/Developer/Worktrees/dav794-r1/target:254 package tests passed, 7 existing ignores; mount and contract each passed; clippy/fmt clean; memory probe passed.
~/dav794-r1-verified.logendsGATES_EXIT=0. All 1,196 source files match the tested VM tree by SHA-256 (excluding VM-only Nix files). An earlier shared-target binary-reuse sample was discarded; these final results come from the isolated target.Decisions: refuse serialized-byte overflow with bounded 507 and no partial success/token; byte-bounded raw sync pages use valid continuation tokens. Admission lasts through response-body drop. No production access, no Nix files committed, no merge. Inherited cold rebuild staging/cache compaction, Apple-native replay and perf-VM latency remain outside this review-fix pass. New-head independent review remains pending, within the three-round maximum.
Independent review, round 2
Reviewed
9a6c56a86f, including the finalized #782 dependency ata59f782e. Defensive review of our own code. Read the common brief, context/taste and relevant ADRs, then concentrated on the fix diff and targeted transport/auth/CardDAV files and tests. No production code changed or pushed; no merge or production access. Temporary probes live only in the isolated dev-01 review worktree.Verdict: fix first. New findings: P0 0, P1 1, P2 1, P3 0. The response-admission finding below is a newly demonstrated hole in the round-1 fix, and means R1-3 is not fully fixed.
address-data, checked-property output and aggregate-report regressions pass. The isolated memory child reads Linux VmHWM, including freed allocations, so it measures the right peak rather than only live memory after response completion. My rerun: 12,908 KiB peak, 112 KiB growth, 68,680-byte input, bounded 400. This input exceeds the 4 KiB lexical-tag bound and exercises early rejection; it does not establish memory bounds for accepted XML, concurrent requests or socket-retained replies. The latter fails below.a59f782eis incorporated.try_acquire_ownedprecedes FIFO admission, and warm-cache bypass remains. The blocked-DB test checks immediate excess rejection on the first poll, cancellation return, FIFO-timeout return and warm success. Targeted rerun passed. This establishes retained cold-request admission; it does not claim that cancellation aborts already-enqueued DB jobs (the separate DB channel is bounded).unread_response_bodies_keep_their_user_admissionholds unpolledoneshotresponses. It never exercises Hyper consuming the frame and retaining its bytes under TCP backpressure. Real TCP clients bypass the response-retention mechanism: R2-1. There is also no upload/readiness deadline: R2-2.Noneremains absence.cal; real CardDAV usesc; router construction rejects conflicting bindings, including the reserved DAV binding. The test in CardDAVread.rs, unlike the remaining CardLike stub test, mounts the real adapter with the calendar stub, parses Depth 0/1 XML namespace-aware and checks both home properties and response counts. Rerun passed.New findings
R2-1 — P1: admission is released while Hyper still retains the large response frame
Location: crates/dav/src/serve.rs:191; inadequate regression at crates/dav/tests/admission.rs:282.
The lease is captured by the
map_frameclosure, not owned by the returned frame's bytes. These replies are a complete buffered byte frame. Hyper polls that frame, drops the exhausted body/closure and keeps the bytes in its connection write buffer while the client stops reading. The permit is available again even though the large allocation remains live. The new 8 MiB per-reply limit therefore does not bound aggregate outstanding response memory: one valid credential can repeat this on arbitrarily many connections, bypassing the shared mechanism intended to enforce the 4/owner and 64/router retention bounds.Real-network reproduction: on dev-01, real CardDAV adapter and real app-password authentication through
axum::serve, one 128 KiB contact, REPORT with 48 repeated hrefs, about 6 MiB per reply. Each client reads only the HTTP headers and keeps its TCP socket open without reading the body. All eight clients receive 207, and a ninth authenticated OPTIONS receives 204, rather than overload refusal. In the isolated single-probe run, RSS grows from 20,192 to 70,776 KiB. The test deliberately stops at eight sockets; no OOM-sized run. Existing unpolled-body admission tests still pass alongside this reproduction.Fix: attach admission ownership to the actual byte allocation so it follows downstream frame clones/slices through the HTTP write buffer, for example an owner-backed
Bytesallocation retaining the lease, or enforce an equivalent budget at the connection/write-completion layer. Merely capturing a permit in another body wrapper has the same lifetime hole. Add a real TCP backpressure regression: more than four nonreading responses for one owner must refuse further admissions while the bytes remain retained, then recover after clients disconnect. Verify the global cap too. A write deadline alone is insufficient to establish the promised concurrent-memory bound during that deadline.R2-2 — P2: incomplete bodies can monopolize the new owner admission indefinitely
Location: crates/dav/src/serve.rs:159, body wait at serve.rs:167; home/readiness waits at
serve.rs:362and:370.After taking admission,
to_bytes(...).awaithas a byte limit but no time limit. Four authenticated requests with a valid Content-Length and an unfinished body can keep all four slots for that credential owner while doing no useful work. Every other installation belonging to that owner, across adapters, gets 429 until the attacker disconnects. Sixteen owners can occupy all 64 router slots. The same absence of a request deadline applies to async home/readiness waits. Normal serving has no compensating deadline:ShutdownIo's write grace starts only on shutdown, and its reads have no runtime idle deadline.The TCP probe sends four PROPFIND headers with Content-Length 1024 and only one body byte: a fifth OPTIONS returns 429, still 429 after one second of inactivity, then 204 after the four clients disconnect. This finite probe establishes slot ownership/release; the indefinite duration follows from the unbounded await and absence of a runtime deadline, not from pretending a one-second wait proves infinity. Existing readiness tests release work by aborting it manually, so they do not prove autonomous recovery.
Fix: enforce bounded body idle and overall read deadlines and an async request/readiness deadline, returning a bounded retryable response and releasing the request lease. When fixing R2-1, also bound response-write lifetime so correctly retained response leases cannot be pinned forever. Keep active blocking work's lease until the work actually ends, even if its HTTP deadline expires. Add controlled-time/deadline tests showing that stalled input/readiness and a nonreading client recover capacity without client cooperation, while legitimate requests still complete.
Verification
All builds/tests ran on calternal-dev-01-compute02, detached worktree
~/Developer/Worktrees/review794-round2at the reviewed commit, Nix shell,~/bin/slot,-j4. No control-host builds/tests/installs. Used target directory/home/claude/Developer/Worktrees/dav794-r1/target; Cargo rebuilt the reviewed crates from the fresh review-worktree paths, as recorded in the logs, rather than relying on a previous test executable.Inside
nix develop -c bash -c, with thatCARGO_TARGET_DIR:The 12 targeted DAV tests and 22 CardDAV read/cache tests passed. Both temporary TCP probes pass by asserting the observed problematic behavior; they reproduce findings, not fixes. The targeted auth admission test passed. Logs:
~/review794-r2.logand~/review794-r2-extra.log. Local read-onlygit diff --check 26936341..9a6c56a8passed. Did not rerun the full application/clippy train.Required before landing: fix R2-1 and R2-2. This is review round 2 of the maximum 3; no additional rounds were started. No new cross-user read, scope widening or XML entity expansion found in the targeted changes.
Round-2 implementation plan: retain admission in owner-backed response Bytes, including downstream clones/slices. Reserve each admitted request’s maximum 8 MiB reply before work against a 64 MiB global response budget (8 reservations), while preserving 4/owner and 64/router ceilings. Use tower-http handler/body timeout layers, plus a DAV-aware listener to enforce write idle and whole-request deadlines through TCP write completion. Defaults: 60 s total, 10 s idle; configurable. Blocking closures retain admission until they actually end. O(body + reply) work, O(admitted requests + bounded bytes) memory.
Gates on dev-01: dav/carddav/auth/server packages, dav_is_mounted, contract, clippy -D warnings, fmt. Final review round 3 remains pending; never merge.
Round 2 implementation status
Pushed
9e95ad41a0tofeat/dav-transport. Both required fixes are implemented and verified. FINAL independent review round 3 remains pending. Never merged.dav_is_mounted/contract/shutdown_io-D warnings/ fmtFinal authoritative dev-01 worktree and target:
/home/claude/Developer/Worktrees/dav794-r2and its owntarget/. All commands ran innix develop -c bash -cthrough one~/bin/slot, never on the control host:~/dav794-r2-final.logends GATES_EXIT=0. The isolated first eight-reader case measured 47,324 KiB VmHWM, 26,328 KiB growth; assertions bound growth below 56 MiB and absolute peak below 96 MiB. The four socket scenarios cover total timeout, idle timeout, global byte pressure and client disconnect. Peak across their sequential allocations was 69,128 KiB. These are process-memory observations, not a claim about all server caches.Failing-before evidence:
~/dav794-r2-red.logfails because client five receives 207 instead of 429 at9a6c56a8. A further controlled-clock regression,~/dav794-r2-anchor-red.log, proves that starting a relative timer only when its task is scheduled extends a 60 s deadline to 120 s; the final code captures an absolute deadline at request entry, and that test passes. An initial new-listener test also caught Hyper flattening when vectored writes were not advertised; queued-write preservation is part of the final design, rather than assuming a byte owner alone is sufficient.Decisions and limits: reserve maximum reply size up front instead of adding dynamic allocation exceptions; defaults therefore allow eight concurrent requests, with four per owner. Configuration is
calternal_dav::Config, shared with the listener. On HTTP/2, deadline expiry closes the shared connection, so other streams retry. Blocking work cannot be forcibly preempted and intentionally retains its charge until it ends. Native Apple replay and perf-VM latency gates remain the previously deferred work; no such results are claimed. No production access or merge. This is an implementation response to round 2, not an additional independent review round.Independent review, round 3 (final)
Reviewed
9e95ad41a0, including rounds 1/2 and implementation status #issuecomment-71076. Defensive review of our own code. Verdict: small fix (P2-or-lower only). New findings: P0 0, P1 0, P2 1, P3 0. The memory/admission fixes hold in the targeted tests; the requested slow-phone compatibility check does not.New finding
R3-1 — P2: response deadlines truncate legitimate progressing syncs, without a resumable result
Locations: connection.rs:179, connection.rs:83, defaults at serve.rs:37.
Scenario: real authenticated CardDAV, 48 distinct valid ~128 KiB cards, one 6,308,392-byte multiget reply, comfortably below the 8 MiB per-reply bound. TCP receiver buffer is 16 KiB. The client reads up to 4 KiB every 125 ms, about 32 KiB/s, for 65 seconds, then drains quickly. There are over 500 successful reads; the client never deliberately pauses for ten seconds. Default 60 s total / 10 s idle returns incomplete XML.
Isolating the two deadlines on the same fixture:
The idle timer measures the interval without a successful application socket write, not absence of delivery to the client. TCP can remain non-writable while its existing send buffer drains continuously to a slow receiver, so this is not a reliable ten-second “client made no progress” detector. Independently, the absolute 60-second timer ends a valid transfer even when the idle window is relaxed. After the 207 headers have been sent, closure leaves truncated XML, not a smaller valid page or continuation. Retrying the same fixed client batch repeats the failure; the 64 MiB aggregate reservation does not help.
Fix: choose and document a supported minimum transfer rate and size the response lifetime and pending-write tolerance for a maximum-size reply at that rate, including TCP buffering. Keep upload/readiness deadlines separate if needed. Preserve the byte-owned reservations and bounded stalled-client recovery. A response-specific configuration with suitable defaults is a small change; do not merely increase the total timeout while leaving the demonstrated idle false positive. Alternatively arrange smaller valid replies before sending headers, with real protocol continuation where supported. Add the continuously reading TCP case alongside the nonreading-client regressions. The main application currently selects library defaults, so a test-only configuration change does not fix deployed behavior.
Severity is P2: this is a slow-link/batch-size-dependent read availability regression, with smaller-request or longer-deadline workarounds, rather than a new memory-bound escape or data-loss finding.
Verification and scope
All builds/tests ran on calternal-dev-01-compute02, detached worktree
~/Developer/Worktrees/review794-round3, exact reviewed HEAD. Used Nix,~/bin/slot,-j4, andCARGO_TARGET_DIR=/home/claude/Developer/Worktrees/dav794-r2/target; logs show recompilation from the round-3 worktree. Tracked application sources are unchanged; only VM-only Nix files and an untracked review probe were added there.Inside
nix develop -c bash -c:Committed regressions: 2 network + 6 admission + 4 connection tests passed. Temporary 5,000-contact probe passed. The first slow probe failed its expectation that increasing only total time would permit completion, exposing the idle issue; the final three-configuration probe passes by asserting the observed truncation/completion outcomes above. These probe assertions reproduce the finding; they do not certify the deadline policy as correct. Logs:
~/review794-r3-existing.log,~/review794-r3-connection.log,~/review794-r3-probes.log,~/review794-r3-slow-isolated.log. Control-host read-onlygit diff --check 9a6c56a8..9e95ad41also passed. Full application/clippy train and native Apple behavior were not rerun or claimed.No new P0/P1 found in this final round, so the mandatory “stop and simplify” trigger is not met. Address R3-1 before landing. No fourth independent review round started. No code pushed, merge, or production access.
R3-1 implementation
Pushed
26edc6476btofeat/dav-transport. This implements the final review’s simpler response-specific size/minimum-rate rule. No fourth review round or merge.Response transmission now gets
min(response_timeout, idle_timeout + reply_bytes / min_response_rate), rounded up to milliseconds. Defaults are 2 KiB/s, 10 s slack, and a 30 min hard cap. The response timer replaces the preparation timer when the buffered reply is ready. Pending socket writes get the same buffer-aware tolerance: a TCP send buffer can keep draining to a reading client despite no successful application write for ten seconds. This fixes both cutoffs demonstrated in round 3, rather than only raising the total deadline.Request-body no-progress timeout remains 10 s; authentication/upload/readiness/preparation remain limited to 60 s. Admission, owner-backed Bytes, 8 MiB reply reservations, 64 MiB global reservation budget and all existing memory/count limits are unchanged. Only the connection policy, config/response handoff, and network regressions changed.
Verification on dev-01, Nix shell through one
~/bin/slot,-j4:-D warningsand fmt passed.9e95ad41failed this regression with truncated XML after 514 reads over 65 s. Fixed run passed.Exact final gates:
Additional focused checks:
cargo test -j4 -p calternal-dav --lib connection:: --locked -- --nocaptureandcargo test -j4 -p calternal-carddav --test network_limits --locked -- --nocapture.Evidence:
~/dav794-r3-red.logand~/dav794-r3-gates.log(endsGATES_EXIT=0). VM worktree:~/Developer/Worktrees/dav794-r3-fix; reused target:/home/claude/Developer/Worktrees/dav794-r2/target, with recompilation from the new worktree recorded in the log. SHA-256 comparison confirms all 1,198 tracked files match the control worktree. VM-only Nix files were not committed.Tradeoff: a stopped reader may hold its existing reservation for the size/rate response budget, up to 30 minutes. The hard cap takes precedence over the configured rate for large replies. This is the reviewer-suggested bounded response policy, with upload/preparation deadlines separate. No additional independent review or native-client claim.
stack refresh after #776/#777 round 1: updated #777
3c8ddf534fmerged intofeat/dav-transport, producing80ec1fa39f. pushed only after all requested gates passed. never merged into dev. no additional independent review round launched.This inherits bounded wire revision retention (default 1,024 changes, configurable Cache retention, expired tokens return RFC 6578 valid-sync-token) and a disk-staged rebuild from bounded 32-card/ID pages. Production code merged cleanly. Two append-only test conflicts were resolved by retaining every transport test and every new retention regression. Existing transport byte/resource limits and socket deadlines remain intact.
app::dav_tests::dav_is_mounted_with_real_scoped_auth_and_contact_projectionplugins::tests::contract_matches_the_serverVM: claude@calternal-dev-01-compute02, fresh isolated worktree and target
/home/claude/Developer/Worktrees/dav794-retention-r1. All heavy commands in Nix through one~/bin/slot,-j4.~/dav794-retention-r1.log;~/dav794-retention-r1.exitis 0.Remaining limits are documented in #777's status: native Apple replay and perf-VM latency gates are not claimed; incremental journal replay still buffers its affected-card set, and per-book readiness can wait for a rebuild. Kill tests exercise staging batch boundaries, not power loss/deterministic interruption inside SQLite backup.
feat/carddav-writes/ #797 was deliberately left unchanged; its write-review implementation can incorporate this updated transport head in its own task. Independent review of the refreshed stack remains pending.Integration note after #776/#777 final review
Reviewed refreshed
21e678b258only for regressions from re-merging #776/#777. This is the requested integration check, not a fourth transport review.verdict: ready within this integration scope. New findings: P0 0, P1 0, P2 0, P3 0. No new P0/P1; no stop-and-simplify trigger.
Diff 80ec1fa3..21e678b2 contains only five cache/regression files; DAV transport, adapter/properties, auth, server/mount, network tests and deadlines are byte-identical. Independent SHA-256 comparison confirms all 446 Rust/Cargo files in
~/Developer/Worktrees/dav794-epoch-r2match21e678b2despite that VM worktree's older Git HEAD. Fresh #776/#777 targeted runs pass (21/25 tests), including both epoch interleavings and HTTP resync. Prior source-matched~/carddav-epoch-final2.loghas all three merged epoch regressions passing, broader transport/auth/socket gates andTRANSPORT_GREEN, exit 0. The attempted fresh #794 rerun remained queued and was cancelled before Cargo started; those prior runtime results are inspected evidence, not a fresh transport pass. Read-only diff/whitespace checks pass.Existing native-client, perf-VM and backup-interruption limits remain. No code pushed or merge. See the final-round comments on #776/#777 for full evidence.
kayg referenced this pull request2026-11-05 23:21:11 +00:00
housekeeping #1009: rebased+failing, left open for review.
restacked only the transport feature on #777. kept dev strict DAV target handling and bounded scope cache; Notes scopes remain separate from the DAV gate. added verify_any for DAV any-scope checks, retained Notes scope separation, and matched current unavailable/503 retry outcome. removed obsolete single-scope helper and added current credentials to DAV transport fixtures.
head:
6458b50031c6bfc1fb52dcf1b480ab3f27506c27; based on devcd7f84432febfc63b788fbb9b9f9950452982d74, pushed with the original exact force-with-lease.frontend frozen install, check, lint, build and unit tests passed. bundle gate passed. first-paint brotli vs dev: JS 230777 B (+0 B), CSS 18386 B (+0 B).
Rust gate results (Mac VM):
cargo fmt -p calternal-auth -p calternal -p calternal-carddav -p calternal-contacts-actions -p calternal-contacts -p calternal-dav -p calternal-notes -- --checkcargo check -j4 --locked -p calternal --binscargo check -j4 --locked -p calternal-auth -p calternal -p calternal-carddav -p calternal-contacts-actions -p calternal-contacts -p calternal-dav -p calternal-notes --all-targetscargo clippy -j4 --locked -p calternal-auth -p calternal -p calternal-carddav -p calternal-contacts-actions -p calternal-contacts -p calternal-dav -p calternal-notes --all-targets -- -D warningscargo test -j4 --locked -p calternal-auth --libcargo test -j4 --locked -p calternal-auth -p calternal -p calternal-carddav -p calternal-contacts-actions -p calternal-contacts -p calternal-dav -p calternal-notescargo check -j4 --locked -p calternal-auth -p calternal-dav -p calternal-carddav -p calternal-contacts-actions -p calternal-contacts --all-targetscargo clippy -j4 --locked -p calternal-auth -p calternal-dav -p calternal-carddav -p calternal-contacts-actions -p calternal-contacts --all-targets -- -D warningscargo test -j4 --locked -p calternal-auth -p calternal-dav -p calternal-carddav -p calternal-contacts-actions -p calternal-contacts --libserver-wide all-target checks/tests are blocked on macOS by
storage_startup.rs:147borrowing Child immutably; clippy also reports unusedstateinstorage.rs:265. both reproduce on dev. scoped auth/DAV/CardDAV/contact component checks, clippy and unit tests passed.all executed gates used the VM Nix environment, shared Mac lock and slot. exact commands, source heads, logs and dev baseline. frontend inputs are identical to the tested frontend tree when a Rust-only repair changed the head.
original-head cherry/patch inventory,
pr-794.md; unmatched entries are missing-patch candidates, with semantic overlap/replacements noted above.View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.Merge
Merge the changes and update on Forgejo.Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.