De-fabrication pass over nuncio-mail and nuncio-cal: no pub production code path in these crates now returns canned data or fabricates success.
Part 1 — orphaned duplicate CardDAV client (deleted)
Deleted crates/nuncio-cal/src/carddav.rs in full (CardDavClient/Contact, ~148 lines). It made no network call, implemented no backend trait, and was a non-functional duplicate of the real, working nuncio_contacts::carddav::CardDavClient.
Removed its mod carddav; / pub use carddav::{CardDavClient, Contact}; lines from crates/nuncio-cal/src/lib.rs.
Verified no dependents: git grep -n "nuncio_cal::CardDavClient\|nuncio_cal::Contact\|nuncio_cal::carddav\|use nuncio_cal" shows only CalDavAccountConfig/CalDavClient/CalendarBackend/MockCalendarBackend usages outside the crate — nothing referenced the deleted module.
Part 2 — credential-less fake-data mail paths (honest error)
ImapEngine::sync_folders / ImapEngine::sync_folder_messages (called from MailBackend::sync_messages): the credential-less branches returned hardcoded Folder/Email fixtures. Changed to return MailError::AuthError ("... requires credentials") instead.
Bonus fix while touching this: even with credentials, sync_folders previously fell back to the same canned folders whenever the real mailbox list came back empty — a genuinely empty mailbox is a valid result, not a signal to fabricate data, so that fallback is removed too.
JmapEngine::sync_folders / JmapEngine::sync_messages: same treatment — the !has_credentials() branches now return MailError::AuthError instead of a hardcoded folder list / a synthetic sample_jmap payload run through the real parser.
MailBackend::send_email: removed from the trait entirely. ImapEngine::send_email discarded the message and returned Ok(()) unconditionally (pure fabricated success — no transport). JmapEngine::send_email checked recipient.is_empty() but otherwise also just returned Ok(()) with no transport. Verified nothing in production calls MailBackend::send_email: git grep -n "\.send_email(" across crates/* shows only test call sites (removed here) and SmtpTransportEngine::send_email (an unrelated inherent method — the real SMTP path used by nunciod::send, driven through the separate MessageSender trait, not MailBackend). mail_backend (Arc<dyn MailBackend>) is only ever probed with .is_some() in grpc.rs, never called for sending.
MockMailBackend::send_email (its MailBackend impl) removed along with the trait method; its unused sent_messages tracking field/getter removed too (dead once the mock stopped implementing send_email). MockMessageSender (used by the real send-path tests) is untouched.
Mechanism chosen and why
CardDAV dup: delete, since it did nothing and had no dependents.
Credential-less sync_folders/sync_messages: honest typed error (MailError::AuthError), not #[cfg(test)]-gating, because ImapEngine::new/JmapEngine::new are legitimate two-step-construction public constructors (paired with set_credentials), not test-only scaffolding — gating them behind #[cfg(test)] would remove a valid construction pattern for external callers of the crate. An honest error is the correct behavior for "you asked me to sync without ever giving me credentials."
send_email: removed from the trait rather than "error honestly," since grep confirmed zero production callers of MailBackend::send_email — the real send path (MessageSender/SmtpTransportEngine) already exists and is exercised end-to-end in nunciod::send. Keeping a dead trait method around only to have it return Unsupported would be a code smell with no behavioral value; removing it is the more honest fix.
Tests migrated (real fixtures, still offline)
nuncio-mail/src/imap.rs: replaced imap_engine_sync_folders_and_messages (asserted on the fabricated fixture + called the now-removed send_email) with:
sync_folders_and_sync_messages_require_credentials — asserts the honest AuthError.
sync_folders_lists_real_mailboxes_over_a_scripted_server — a new test driving MailBackend::sync_folders against a real plain-TCP loopback IMAP server scripted to answer LOGIN/LIST/LOGOUT, proving the folder list is genuinely read off the wire (mirrors the existing tokio::io::duplex scripted-server pattern already used elsewhere in the file for sync_folder_messages_with_session).
nuncio-mail/src/jmap.rs: replaced uncredentialed_engine_keeps_static_fallback_behaviour with uncredentialed_engine_requires_credentials_to_sync, asserting the honest AuthError for both sync_folders and sync_messages. The existing wiremock suite (tests/wiremock_jmap_test.rs) already fully covers the credentialed real-HTTP path through the MailBackend trait (jmap_engine_sync_folders_and_messages_through_mail_backend_trait) and was untouched.
nuncio-mail/src/mock.rs: dropped the send_email/sent_messages assertions from mock_backend_folder_and_message_operations (method no longer exists); MockMessageSender's own send test is untouched.
No live network in any test — the IMAP test uses a real loopback TCP socket with a scripted responder (no external I/O); JMAP credentialed behavior is wiremock-backed (already existed, untouched).
Grep-verified no production dependents before deleting nuncio-cal/src/carddav.rs
Grep-verified no production callers of MailBackend::send_email before removing it from the trait
Closes #253.
## Summary
De-fabrication pass over `nuncio-mail` and `nuncio-cal`: no `pub` production code path in these crates now returns canned data or fabricates success.
### Part 1 — orphaned duplicate CardDAV client (deleted)
- Deleted `crates/nuncio-cal/src/carddav.rs` in full (`CardDavClient`/`Contact`, ~148 lines). It made no network call, implemented no backend trait, and was a non-functional duplicate of the real, working `nuncio_contacts::carddav::CardDavClient`.
- Removed its `mod carddav;` / `pub use carddav::{CardDavClient, Contact};` lines from `crates/nuncio-cal/src/lib.rs`.
- **Verified no dependents**: `git grep -n "nuncio_cal::CardDavClient\|nuncio_cal::Contact\|nuncio_cal::carddav\|use nuncio_cal"` shows only `CalDavAccountConfig`/`CalDavClient`/`CalendarBackend`/`MockCalendarBackend` usages outside the crate — nothing referenced the deleted module.
### Part 2 — credential-less fake-data mail paths (honest error)
- `ImapEngine::sync_folders` / `ImapEngine::sync_folder_messages` (called from `MailBackend::sync_messages`): the credential-less branches returned hardcoded `Folder`/`Email` fixtures. Changed to return `MailError::AuthError` ("... requires credentials") instead.
- Bonus fix while touching this: even *with* credentials, `sync_folders` previously fell back to the same canned folders whenever the real mailbox list came back empty — a genuinely empty mailbox is a valid result, not a signal to fabricate data, so that fallback is removed too.
- `JmapEngine::sync_folders` / `JmapEngine::sync_messages`: same treatment — the `!has_credentials()` branches now return `MailError::AuthError` instead of a hardcoded folder list / a synthetic `sample_jmap` payload run through the real parser.
- `MailBackend::send_email`: removed from the trait entirely. `ImapEngine::send_email` discarded the message and returned `Ok(())` unconditionally (pure fabricated success — no transport). `JmapEngine::send_email` checked `recipient.is_empty()` but otherwise also just returned `Ok(())` with no transport. **Verified nothing in production calls `MailBackend::send_email`**: `git grep -n "\.send_email("` across `crates/*` shows only test call sites (removed here) and `SmtpTransportEngine::send_email` (an unrelated *inherent* method — the real SMTP path used by `nunciod::send`, driven through the separate `MessageSender` trait, not `MailBackend`). `mail_backend` (`Arc<dyn MailBackend>`) is only ever probed with `.is_some()` in `grpc.rs`, never called for sending.
- `MockMailBackend::send_email` (its `MailBackend` impl) removed along with the trait method; its unused `sent_messages` tracking field/getter removed too (dead once the mock stopped implementing `send_email`). `MockMessageSender` (used by the real send-path tests) is untouched.
### Mechanism chosen and why
- CardDAV dup: **delete**, since it did nothing and had no dependents.
- Credential-less `sync_folders`/`sync_messages`: **honest typed error** (`MailError::AuthError`), not `#[cfg(test)]`-gating, because `ImapEngine::new`/`JmapEngine::new` are legitimate two-step-construction public constructors (paired with `set_credentials`), not test-only scaffolding — gating them behind `#[cfg(test)]` would remove a valid construction pattern for external callers of the crate. An honest error is the correct behavior for "you asked me to sync without ever giving me credentials."
- `send_email`: **removed from the trait** rather than "error honestly," since grep confirmed zero production callers of `MailBackend::send_email` — the real send path (`MessageSender`/`SmtpTransportEngine`) already exists and is exercised end-to-end in `nunciod::send`. Keeping a dead trait method around only to have it return `Unsupported` would be a code smell with no behavioral value; removing it is the more honest fix.
### Tests migrated (real fixtures, still offline)
- `nuncio-mail/src/imap.rs`: replaced `imap_engine_sync_folders_and_messages` (asserted on the fabricated fixture + called the now-removed `send_email`) with:
- `sync_folders_and_sync_messages_require_credentials` — asserts the honest `AuthError`.
- `sync_folders_lists_real_mailboxes_over_a_scripted_server` — a new test driving `MailBackend::sync_folders` against a real plain-TCP loopback IMAP server scripted to answer `LOGIN`/`LIST`/`LOGOUT`, proving the folder list is genuinely read off the wire (mirrors the existing `tokio::io::duplex` scripted-server pattern already used elsewhere in the file for `sync_folder_messages_with_session`).
- `nuncio-mail/src/jmap.rs`: replaced `uncredentialed_engine_keeps_static_fallback_behaviour` with `uncredentialed_engine_requires_credentials_to_sync`, asserting the honest `AuthError` for both `sync_folders` and `sync_messages`. The existing wiremock suite (`tests/wiremock_jmap_test.rs`) already fully covers the credentialed real-HTTP path through the `MailBackend` trait (`jmap_engine_sync_folders_and_messages_through_mail_backend_trait`) and was untouched.
- `nuncio-mail/src/mock.rs`: dropped the `send_email`/`sent_messages` assertions from `mock_backend_folder_and_message_operations` (method no longer exists); `MockMessageSender`'s own send test is untouched.
- No live network in any test — the IMAP test uses a real loopback TCP socket with a scripted responder (no external I/O); JMAP credentialed behavior is wiremock-backed (already existed, untouched).
## Gate output
```
$ cargo fmt --all -- --check
(clean, no output)
$ cargo check-all
Finished `dev` profile [unoptimized + debuginfo] target(s) in 4.62s
(zero warnings)
$ cargo test-all
nuncio-cal: 25 passed (23 unit + 2 wiremock), 0 failed, 0 ignored
nuncio-mail: 56 passed (53 unit + 3 wiremock), 0 failed, 0 ignored
nunciod: 120 unit + 13 integration (e2e) passed, 0 failed, 0 ignored
(full workspace: 0 failed, 0 ignored)
```
Local pre-commit hook (fmt + clippy `--all-targets -D warnings` + full test suite) ran and passed on commit `c990348`.
## Test plan
- [x] `cargo fmt --all -- --check`
- [x] `cargo check-all` (clippy `--all-targets --workspace -D warnings`, 0 warnings)
- [x] `cargo test-all` (0 failed, 0 ignored)
- [x] Grep-verified no production dependents before deleting `nuncio-cal/src/carddav.rs`
- [x] Grep-verified no production callers of `MailBackend::send_email` before removing it from the trait
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.
Closes #253.
Summary
De-fabrication pass over
nuncio-mailandnuncio-cal: nopubproduction code path in these crates now returns canned data or fabricates success.Part 1 — orphaned duplicate CardDAV client (deleted)
crates/nuncio-cal/src/carddav.rsin full (CardDavClient/Contact, ~148 lines). It made no network call, implemented no backend trait, and was a non-functional duplicate of the real, workingnuncio_contacts::carddav::CardDavClient.mod carddav;/pub use carddav::{CardDavClient, Contact};lines fromcrates/nuncio-cal/src/lib.rs.git grep -n "nuncio_cal::CardDavClient\|nuncio_cal::Contact\|nuncio_cal::carddav\|use nuncio_cal"shows onlyCalDavAccountConfig/CalDavClient/CalendarBackend/MockCalendarBackendusages outside the crate — nothing referenced the deleted module.Part 2 — credential-less fake-data mail paths (honest error)
ImapEngine::sync_folders/ImapEngine::sync_folder_messages(called fromMailBackend::sync_messages): the credential-less branches returned hardcodedFolder/Emailfixtures. Changed to returnMailError::AuthError("... requires credentials") instead.sync_folderspreviously fell back to the same canned folders whenever the real mailbox list came back empty — a genuinely empty mailbox is a valid result, not a signal to fabricate data, so that fallback is removed too.JmapEngine::sync_folders/JmapEngine::sync_messages: same treatment — the!has_credentials()branches now returnMailError::AuthErrorinstead of a hardcoded folder list / a syntheticsample_jmappayload run through the real parser.MailBackend::send_email: removed from the trait entirely.ImapEngine::send_emaildiscarded the message and returnedOk(())unconditionally (pure fabricated success — no transport).JmapEngine::send_emailcheckedrecipient.is_empty()but otherwise also just returnedOk(())with no transport. Verified nothing in production callsMailBackend::send_email:git grep -n "\.send_email("acrosscrates/*shows only test call sites (removed here) andSmtpTransportEngine::send_email(an unrelated inherent method — the real SMTP path used bynunciod::send, driven through the separateMessageSendertrait, notMailBackend).mail_backend(Arc<dyn MailBackend>) is only ever probed with.is_some()ingrpc.rs, never called for sending.MockMailBackend::send_email(itsMailBackendimpl) removed along with the trait method; its unusedsent_messagestracking field/getter removed too (dead once the mock stopped implementingsend_email).MockMessageSender(used by the real send-path tests) is untouched.Mechanism chosen and why
sync_folders/sync_messages: honest typed error (MailError::AuthError), not#[cfg(test)]-gating, becauseImapEngine::new/JmapEngine::neware legitimate two-step-construction public constructors (paired withset_credentials), not test-only scaffolding — gating them behind#[cfg(test)]would remove a valid construction pattern for external callers of the crate. An honest error is the correct behavior for "you asked me to sync without ever giving me credentials."send_email: removed from the trait rather than "error honestly," since grep confirmed zero production callers ofMailBackend::send_email— the real send path (MessageSender/SmtpTransportEngine) already exists and is exercised end-to-end innunciod::send. Keeping a dead trait method around only to have it returnUnsupportedwould be a code smell with no behavioral value; removing it is the more honest fix.Tests migrated (real fixtures, still offline)
nuncio-mail/src/imap.rs: replacedimap_engine_sync_folders_and_messages(asserted on the fabricated fixture + called the now-removedsend_email) with:sync_folders_and_sync_messages_require_credentials— asserts the honestAuthError.sync_folders_lists_real_mailboxes_over_a_scripted_server— a new test drivingMailBackend::sync_foldersagainst a real plain-TCP loopback IMAP server scripted to answerLOGIN/LIST/LOGOUT, proving the folder list is genuinely read off the wire (mirrors the existingtokio::io::duplexscripted-server pattern already used elsewhere in the file forsync_folder_messages_with_session).nuncio-mail/src/jmap.rs: replaceduncredentialed_engine_keeps_static_fallback_behaviourwithuncredentialed_engine_requires_credentials_to_sync, asserting the honestAuthErrorfor bothsync_foldersandsync_messages. The existing wiremock suite (tests/wiremock_jmap_test.rs) already fully covers the credentialed real-HTTP path through theMailBackendtrait (jmap_engine_sync_folders_and_messages_through_mail_backend_trait) and was untouched.nuncio-mail/src/mock.rs: dropped thesend_email/sent_messagesassertions frommock_backend_folder_and_message_operations(method no longer exists);MockMessageSender's own send test is untouched.Gate output
Local pre-commit hook (fmt + clippy
--all-targets -D warnings+ full test suite) ran and passed on commitc990348.Test plan
cargo fmt --all -- --checkcargo check-all(clippy--all-targets --workspace -D warnings, 0 warnings)cargo test-all(0 failed, 0 ignored)nuncio-cal/src/carddav.rsMailBackend::send_emailbefore removing it from the trait