Skip to content

Keep saved named-group rosters out of message history - #176

Merged
erikwb merged 2 commits into
mainfrom
fix/named-group-rosters
Sep 27, 2026
Merged

erikwb merged 2 commits into
mainfrom
fix/named-group-rosters

Conversation

@erikwb

@erikwb erikwb commented Sep 27, 2026

Copy link
Copy Markdown
Owner

Addresses the "keeps losing group members" part of #174.

The bug

When you confirm a reply roster for a named group, set_group_participants saved it to history as an ordinary group_route event. That makes it disposable while the group is still in use:

  • Conversation window: conversations are projected from only the newest 2,000 history events (MAX_CONVERSATION_EVENTS). Each group message is two events (MAP + ANCS), so after roughly 1,000 messages the saved roster fell out of view and the thread went back to asking for participants.
  • Retention: the roster record has a seen_at timestamp, so the 30-day sweep deleted it outright.
  • The re-prompt: once the roster was gone, the prompt was pre-filled only with senders still inside the window. The user sees this as members "disappearing".

The fix

  • GroupRoutesStore (group_routes.py) keeps one roster per named-group key as an encrypted preference in settings.json, like starred threads and group confirmations. It is bounded to 200 rosters.
  • Every projection applies the stored rosters after history, so they win over any legacy record. When a thread is saved under a new key, rosters under its alias keys are replaced.
  • Storage preparation moves legacy group_route events out of history before pruning. If a roster was saved in both places, the store's copy wins.
  • Deleting a conversation, clearing history, or changing the storage mode still removes its roster.

Also in this PR

Keep tests away from the operator's BlueFerry state: conftest now points XDG_CONFIG_HOME, XDG_STATE_HOME, and XDG_RUNTIME_DIR at a throwaway directory before anything imports blueferry. Previously, a test that undid its own monkeypatching (for example with monkeypatch.undo()) fell back to the real ~/.local/state/blueferry and loaded the real local.env. This happened once during development; nothing was modified.

Not addressed

Group messages still land in one-to-one threads whenever the matching ANCS notification is missing. MAP carries no group identity, so nothing can be fixed on the BlueFerry side without more information. The README now explains this.

Validation

  • 1452 tests pass on a private bus, and each commit passes on its own. Ruff, mypy, and Bandit pass.
  • New tests reproduce both loss paths, the window and retention. Both fail against the old behavior.
  • Other new tests cover the legacy migration, the store winning over a legacy record, the erase paths, and encryption at rest.
  • No live-phone testing.

blueferry.config derives its default configuration and state paths from
the real XDG directories at import. A test that undid its own isolation
(for example with monkeypatch.undo()) fell back to the operator's real
history, contact cache, settings, and local.env.

Point XDG_CONFIG_HOME, XDG_STATE_HOME, and XDG_RUNTIME_DIR at a
throwaway tree before anything imports blueferry, as the suite already
does for D-Bus addresses.
Addresses the roster loss in #174. A confirmed reply roster for a named group was appended to
history as an ordinary event, so it was lost in three ways while the
group was still active:

- conversations are projected from only the newest 2,000 history
  events, so after roughly 1,000 messages the saved roster fell out of
  view and the thread asked for participants again;
- the 30-day retention sweep deleted it outright;
- the re-prompt was pre-filled only with senders still in the window,
  so members appeared to disappear over time.

Store rosters as an encrypted preference in settings.json, like starred
threads and group confirmations, and apply them to every projection.
Storage preparation moves rosters saved by older releases out of history
before pruning. Deleting a conversation, clearing history, or changing
the storage mode still removes its roster.
@erikwb
erikwb merged commit ce00c20 into main Sep 27, 2026
3 of 4 checks passed
@erikwb
erikwb deleted the fix/named-group-rosters branch September 27, 2026 15:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant