Contacts sync had a real, wiremock-tested CardDAV client that production
could never reach: `AccountConfig` had no way to express a CardDAV
address book, so `Contacts/Sync` always fell to its honest-error branch
unless a test double was injected.
Add CardDAV as a first-class account protocol, mirroring how CalDAV is
already resolved and driven:
- `AccountProtocol::CardDav` and `Transport::CardDav(DavTransport)`, plus
`is_caldav()`/`is_carddav()` so callers pick a specific DAV flavour
rather than the ambiguous `is_dav()`. Calendar sync now filters on
`is_caldav()` so a CardDAV account can never be mistaken for a calendar.
- Persistence reuses the existing `collection_url` column, distinguished
by the `protocol` discriminator; no schema change.
- Proto gains `ACCOUNT_PROTOCOL_CARDDAV` and a `carddav` transport case
(both additive), with the committed descriptor golden regenerated.
- `contacts_sync::sync_carddav_account` builds a real `CardDavClient` from
the persisted collection URL and a credential read just-in-time from the
OS keyring, zeroized on drop.
- `Contacts/Sync` resolves configured CardDAV accounts and returns a typed
`NotConfigured` (FAILED_PRECONDITION) when none matches -- including
when the named account exists but speaks another protocol -- instead of
an untyped internal error or a fabricated zero count.
- `account add --protocol carddav --collection-url ...` in the CLI.
Offline E2E proves the production path: a CardDAV account added over the
real Accounts API, synced through a real client against wiremock, with
credentials resolved from a mocked vault.
Refs #255