The picker opened on "No contacts in this address book" — about an address book with contacts in it. Nothing was wrong with the button, which is why it read as one: it opened, correctly, onto nothing.
Cause
Contacts are fetched on demand. loadAll runs when the Contacts view mounts, and suggest kicks it off itself — which is why autocomplete has always worked from anywhere. The picker did neither.
So opening a composer without having visited Contacts first showed an empty list over a full account. That's most of the time, and every time in a fresh tab. Anyone who had been to Contacts that session saw it work — the sort of difference that reads as browser-specific when it isn't.
It asks for them now, and says it's loading rather than that there are none.
Also
The picker decided which shared books to offer on isSubscribed alone. Stalwart refuses that flag on a book shared read-only, so those are recorded in settings instead — for an address book that's the only record — and filtering on the server's flag left every shared book out of the picker while the sidebar showed it. Both now ask the same question.
Verified
Against the mock from a genuinely cold store — cards emptied, loaded false, opening the picker as the first thing that wants them: eight rows, from the reader's own book and a shared one, where before there were none.
Confirmed on production first that the button and handler were fine and the dialog was simply empty, so the fix went where the fault was.
333 web and 77 server tests pass. npm run typecheck clean.
The picker opened on **"No contacts in this address book"** — about an address book with contacts in it. Nothing was wrong with the button, which is why it read as one: it opened, correctly, onto nothing.
### Cause
Contacts are fetched on demand. `loadAll` runs when the Contacts view mounts, and `suggest` kicks it off itself — which is why autocomplete has always worked from anywhere. The picker did neither.
So opening a composer without having visited Contacts first showed an empty list over a full account. That's most of the time, and every time in a fresh tab. Anyone who *had* been to Contacts that session saw it work — the sort of difference that reads as browser-specific when it isn't.
It asks for them now, and says it's loading rather than that there are none.
### Also
The picker decided which shared books to offer on `isSubscribed` alone. Stalwart refuses that flag on a book shared read-only, so those are recorded in settings instead — for an address book that's the **only** record — and filtering on the server's flag left every shared book out of the picker while the sidebar showed it. Both now ask the same question.
### Verified
Against the mock from a genuinely cold store — cards emptied, `loaded` false, opening the picker as the first thing that wants them: eight rows, from the reader's own book and a shared one, where before there were none.
Confirmed on production first that the button and handler were fine and the dialog was simply empty, so the fix went where the fault was.
333 web and 77 server tests pass. `npm run typecheck` clean.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
**Merged** 2026-08-27 as coffey-labs/ihasmail@298264aeb800
<sub>Rebuilt from: git history, session transcript.</sub>
This repo is archived. You cannot comment on issues.
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.
The picker opened on "No contacts in this address book" — about an address book with contacts in it. Nothing was wrong with the button, which is why it read as one: it opened, correctly, onto nothing.
Cause
Contacts are fetched on demand.
loadAllruns when the Contacts view mounts, andsuggestkicks it off itself — which is why autocomplete has always worked from anywhere. The picker did neither.So opening a composer without having visited Contacts first showed an empty list over a full account. That's most of the time, and every time in a fresh tab. Anyone who had been to Contacts that session saw it work — the sort of difference that reads as browser-specific when it isn't.
It asks for them now, and says it's loading rather than that there are none.
Also
The picker decided which shared books to offer on
isSubscribedalone. Stalwart refuses that flag on a book shared read-only, so those are recorded in settings instead — for an address book that's the only record — and filtering on the server's flag left every shared book out of the picker while the sidebar showed it. Both now ask the same question.Verified
Against the mock from a genuinely cold store — cards emptied,
loadedfalse, opening the picker as the first thing that wants them: eight rows, from the reader's own book and a shared one, where before there were none.Confirmed on production first that the button and handler were fine and the dialog was simply empty, so the fix went where the fault was.
333 web and 77 server tests pass.
npm run typecheckclean.🤖 Generated with Claude Code
Merged 2026-08-27 as coffey-labs/ihasmail@298264aeb8
Rebuilt from: git history, session transcript.