Contacts/Sync (grpc.rs:1049, contacts_sync.rs:8) is non-functional in production for the same reason as Calendar: no per-account CardDAV config, so prod always hits the honest-error branch and works only via injected mock. Goal: add CardDAV account configuration (endpoint + keyring creds) and construct a REAL CardDavClient (nuncio-contacts/src/carddav.rs) in the Contacts/Sync path from it. Offline E2E (wiremock CardDAV) proving the production path. Coordinate with the dup-CardDAV deletion (M6.5 P0).
Source: full-tree audit 2026-07-30 (scratchpad/audit/AUDIT-SUMMARY.md). Follow docs/STORY-WORKFLOW.md: engine+proto(if surface)+CLI+offline E2E, mock-only tests, no fabricated data, comment convention, PR to dev, PO reviews before close.
Contacts/Sync (grpc.rs:1049, contacts_sync.rs:8) is non-functional in production for the same reason as Calendar: no per-account CardDAV config, so prod always hits the honest-error branch and works only via injected mock. Goal: add CardDAV account configuration (endpoint + keyring creds) and construct a REAL CardDavClient (nuncio-contacts/src/carddav.rs) in the Contacts/Sync path from it. Offline E2E (wiremock CardDAV) proving the production path. Coordinate with the dup-CardDAV deletion (M6.5 P0).
Source: full-tree audit 2026-07-30 (scratchpad/audit/AUDIT-SUMMARY.md). Follow docs/STORY-WORKFLOW.md: engine+proto(if surface)+CLI+offline E2E, mock-only tests, no fabricated data, comment convention, PR to dev, PO reviews before close.
Account-model decision (owner): SEPARATE account entries per service. A CalDAV/CardDAV account is its own AddAccount entry with protocol=CALDAV/CARDDAV + a fully-qualified collection URL + its own keyring credential, decoupled from mail accounts. Implemented additively: new AccountProtocol variant(s) + a generic AccountConfig.collection_url field (reused by both). #254 adds CALDAV + the collection_url field/column; #255 reuses collection_url + adds CARDDAV. Both are [PROTO] -> serialize (#254 first). Depends on #254 landing the collection_url field + the CALDAV precedent.
Account-model decision (owner): SEPARATE account entries per service. A CalDAV/CardDAV account is its own AddAccount entry with protocol=CALDAV/CARDDAV + a fully-qualified collection URL + its own keyring credential, decoupled from mail accounts. Implemented additively: new AccountProtocol variant(s) + a generic AccountConfig.collection_url field (reused by both). #254 adds CALDAV + the collection_url field/column; #255 reuses collection_url + adds CARDDAV. Both are [PROTO] -> serialize (#254 first). Depends on #254 landing the collection_url field + the CALDAV precedent.
Fixed in #431 (e444ffd), merged to dev. Contacts sync is production-wired end to end: a configured CardDAV account now actually syncs.
AccountProtocol::CardDav + Transport::CardDav(DavTransport), reusing the existing collection_url column — no schema change. Proto additions are purely additive (ACCOUNT_PROTOCOL_CARDDAV = 4, carddav oneof at field 19) with the golden regenerated from the build output. contacts_sync::sync_carddav_account builds a real CardDavClient with the credential read just-in-time from the keyring and zeroized. Contacts/Sync now returns a typed NotConfigured/FAILED_PRECONDITION instead of an untyped internal error. CLI gains --protocol carddav. The Contacts service and contact sync command already existed; no RPC was duplicated.
Reviewer note worth carrying forward:is_dav() now covers CardDAV too, so calendar sync's filter moved to the new is_caldav(). That preserves existing behaviour — without it a CardDAV account would have been swept into Calendar/Sync — but it is a real edit to an existing vertical.
Noticed and left alone: nuncio-contacts/src/db.rs still exports an unused ContactsDatabase that nuncio-store's own comment calls superseded. Dead surface, a candidate for the next de-fabrication pass.
Fixed in #431 (`e444ffd`), merged to `dev`. Contacts sync is production-wired end to end: a configured CardDAV account now actually syncs.
`AccountProtocol::CardDav` + `Transport::CardDav(DavTransport)`, reusing the existing `collection_url` column — **no schema change**. Proto additions are purely additive (`ACCOUNT_PROTOCOL_CARDDAV = 4`, `carddav` oneof at field 19) with the golden regenerated from the build output. `contacts_sync::sync_carddav_account` builds a real `CardDavClient` with the credential read just-in-time from the keyring and zeroized. `Contacts/Sync` now returns a typed `NotConfigured`/`FAILED_PRECONDITION` instead of an untyped internal error. CLI gains `--protocol carddav`. The `Contacts` service and `contact sync` command already existed; no RPC was duplicated.
**Reviewer note worth carrying forward:** `is_dav()` now covers CardDAV too, so calendar sync's filter moved to the new `is_caldav()`. That *preserves* existing behaviour — without it a CardDAV account would have been swept into `Calendar/Sync` — but it is a real edit to an existing vertical.
Noticed and left alone: `nuncio-contacts/src/db.rs` still exports an unused `ContactsDatabase` that `nuncio-store`'s own comment calls superseded. Dead surface, a candidate for the next de-fabrication pass.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Contacts/Sync (grpc.rs:1049, contacts_sync.rs:8) is non-functional in production for the same reason as Calendar: no per-account CardDAV config, so prod always hits the honest-error branch and works only via injected mock. Goal: add CardDAV account configuration (endpoint + keyring creds) and construct a REAL CardDavClient (nuncio-contacts/src/carddav.rs) in the Contacts/Sync path from it. Offline E2E (wiremock CardDAV) proving the production path. Coordinate with the dup-CardDAV deletion (M6.5 P0).
Source: full-tree audit 2026-07-30 (scratchpad/audit/AUDIT-SUMMARY.md). Follow docs/STORY-WORKFLOW.md: engine+proto(if surface)+CLI+offline E2E, mock-only tests, no fabricated data, comment convention, PR to dev, PO reviews before close.
Account-model decision (owner): SEPARATE account entries per service. A CalDAV/CardDAV account is its own AddAccount entry with protocol=CALDAV/CARDDAV + a fully-qualified collection URL + its own keyring credential, decoupled from mail accounts. Implemented additively: new AccountProtocol variant(s) + a generic AccountConfig.collection_url field (reused by both). #254 adds CALDAV + the collection_url field/column; #255 reuses collection_url + adds CARDDAV. Both are [PROTO] -> serialize (#254 first). Depends on #254 landing the collection_url field + the CALDAV precedent.
Fixed in #431 (
e444ffd), merged todev. Contacts sync is production-wired end to end: a configured CardDAV account now actually syncs.AccountProtocol::CardDav+Transport::CardDav(DavTransport), reusing the existingcollection_urlcolumn — no schema change. Proto additions are purely additive (ACCOUNT_PROTOCOL_CARDDAV = 4,carddavoneof at field 19) with the golden regenerated from the build output.contacts_sync::sync_carddav_accountbuilds a realCardDavClientwith the credential read just-in-time from the keyring and zeroized.Contacts/Syncnow returns a typedNotConfigured/FAILED_PRECONDITIONinstead of an untyped internal error. CLI gains--protocol carddav. TheContactsservice andcontact synccommand already existed; no RPC was duplicated.Reviewer note worth carrying forward:
is_dav()now covers CardDAV too, so calendar sync's filter moved to the newis_caldav(). That preserves existing behaviour — without it a CardDAV account would have been swept intoCalendar/Sync— but it is a real edit to an existing vertical.Noticed and left alone:
nuncio-contacts/src/db.rsstill exports an unusedContactsDatabasethatnuncio-store's own comment calls superseded. Dead surface, a candidate for the next de-fabrication pass.