Skip to content

fix(desktop): preserve theme when opening communities - #5266

Merged
wesbillman merged 2 commits into
mainfrom
tho/onboarding-theme-hydration-race
Aug 11, 2026
Merged

fix(desktop): preserve theme when opening communities#5266
wesbillman merged 2 commits into
mainfrom
tho/onboarding-theme-hydration-race

Conversation

@tellaho

@tellaho tellaho commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Category: fix
User Impact: Previously selected community themes are preserved when opening a relay through onboarding, while first-time theme migration still completes for communities with no saved theme.

Problem: During community initialization, desktop queried theme history before establishing live delivery. If a replacement event arrived while an empty history query was in flight, the client could incorrectly treat the theme as absent and publish the default over the user's saved selection.

Solution: Subscribe before fetching history, expose whether live readiness reached EOSE, flush buffered live events before resolving EOSE, and retain the newest delivered replacement through hydration. Seed the inherited/default theme only when both live and history snapshots reach EOSE with no valid or unreadable event; subscription failures, CLOSED, readiness timeout, relay failure, and unreadable events fail closed without publishing.

File changes

desktop/src/shared/api/relayClientSession.ts / relayClientShared.ts / relayClosedRecovery.ts
Distinguish EOSE from CLOSED/timeout readiness and flush buffered events before resolving an EOSE fence.

desktop/src/shared/theme/CommunityThemeController.tsx
Seed and complete first-community migration only for confirmed absence; uncertain hydration remains non-publishing.

desktop/src/shared/theme/communityThemePreference.ts
Keep the inherited appearance for the first migrated community and the stable default for later empty communities.

desktop/src/shared/theme/communityThemeSync.ts
Arbitrate live and history results into valid, confirmed-absent, invalid, or unavailable hydration outcomes.

Tests
Cover EOSE/CLOSED readiness, subscription failure, timeout, unreadable and live-racing events, no-op initialization, and first-to-later community fallback isolation.

Reproduction steps

  1. Save a non-default appearance for a community relay.
  2. Remove the community locally, then open the same relay again through onboarding.
  3. Arrange for the saved replacement event to arrive live while the initial history query returns empty.
  4. Confirm the saved appearance remains selected and the client does not publish the default theme over it.
  5. On an account with no theme records, open a first empty community and confirm its inherited appearance is migrated; open a later empty community and confirm it starts from the stable default.

Validation

  • Pre-push desktop checks, typecheck, and full desktop tests: passed at f79556b0e
  • Focused theme/relay readiness tests: 38 passed
  • Desktop file-size ratchet and diff check: passed

@tellaho
tellaho force-pushed the tho/onboarding-theme-hydration-race branch from 5dfeb30 to 1aa0619 Compare August 10, 2026 22:45
Subscribe before fetching relay history, classify programmatic initialization even when appearance application is a no-op, and fail closed on missing or uncertain startup state so delayed replacements cannot be overwritten by an automatic fallback publish.

Co-authored-by: Taylor Ho <taylorkmho@gmail.com>

Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
@tellaho
tellaho force-pushed the tho/onboarding-theme-hydration-race branch from 1aa0619 to 65e5b25 Compare August 10, 2026 22:49
@tellaho
tellaho marked this pull request as ready for review August 10, 2026 23:12
@tellaho
tellaho requested a review from a team as a code owner August 10, 2026 23:12

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewing on Wes's behalf. The subscription-first arbitration is sound, but this patch removes the only successful-absence migration path entirely. On an account with no remote/local/outbox theme, hydration now does nothing: it neither persists the first community's inherited global appearance nor calls markCommunityThemeMigrated. Because that marker remains false, every later community with no record continues using initialPreferenceRef.current instead of the stable default, contrary to the controller's scope-isolation contract. This is a user-visible regression for accounts without an existing relay theme, not merely a documentation issue. Please preserve fail-closed behavior for uncertain states while adding a trustworthy confirmed-absence path that completes migration/seeding, and cover the controller-level sequence: first absent community migrates the inherited appearance; a later absent community receives DEFAULT_COMMUNITY_THEME rather than the first community's appearance. The PR body also currently says a default is seeded when neither source finds a preference, but this head never seeds on hydration.

Comment thread desktop/src/shared/theme/CommunityThemeController.tsx Outdated
Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
Signed-off-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewing on Wes's behalf. The code path is clean in my re-review, but the current head cannot merge under this repo's authorship policy: commit f79556b0ef37850cd7cfe3a63acf30fe23749e3b is authored and signed off by Carl. For block/buzz changes made on Wes's behalf, Wes must be the commit author and Signed-off-by, with the implementing agent only in Co-authored-by.

Please rewrite that commit so its author and sign-off are Wes <wesbillman@users.noreply.github.com>, retaining Carl as co-author, then force-push and let CI/DCO validate the rewritten head. This is my mistake from the implementation pass, not Taylor's.

@wesbillman
wesbillman dismissed stale reviews from themself August 11, 2026 15:08

Dismissed after re-review: the behavioral issue is fixed, and Wes explicitly accepts the current commit attribution.

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review by Carl on Wes's behalf at exact head f79556b0ef37850cd7cfe3a63acf30fe23749e3b: the prior behavioral blocker is fixed and no code findings remain. Wes explicitly accepts the current Carl-authored commit attribution, so I have dismissed both stale changes-requested reviews. The PR is mergeable and all applicable checks are green. Per policy, Wes retains approval authority.

@wesbillman
wesbillman merged commit 83ca595 into main Aug 11, 2026
26 checks passed
@wesbillman
wesbillman deleted the tho/onboarding-theme-hydration-race branch August 11, 2026 15:21
tlongwell-block pushed a commit that referenced this pull request Aug 11, 2026
* origin/main:
  chore: mesh upgrade, clean up legacy special case code, simplify model selection for mesh (#5289)
  fix(desktop): preserve theme when opening communities (#5266)
  fix(link-preview): resolve YouTube videos through oEmbed (#5520)
  fix(buzz-agent): harden Databricks OAuth token cache and callback (#5534)

Signed-off-by: Eva <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz>
Co-authored-by: Eva <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz>
Signed-off-by: Eva <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz>
atishpatel pushed a commit that referenced this pull request Aug 11, 2026
…overy

* origin/main:
  Add glass appearance and cohesive settings (#5478)
  Add Send to channel for thread messages (#5305)
  Fix macOS attachment picker lifecycle and allow inert HTML downloads (#5569)
  fix(desktop): preserve fresh channel timelines (#5577)
  fix(desktop): suppress fresh focus-return refetches for channels and home-feed (#5535)
  chore: mesh upgrade, clean up legacy special case code, simplify model selection for mesh (#5289)
  fix(desktop): preserve theme when opening communities (#5266)
  fix(link-preview): resolve YouTube videos through oEmbed (#5520)
  fix(buzz-agent): harden Databricks OAuth token cache and callback (#5534)

Signed-off-by: Hardworking Honey <c5c455215c2506cb8ba776518cec804af62d3a0526e32d496a22072e395042b9@buzz.block.builderlab.xyz>
wpfleger96 added a commit that referenced this pull request Aug 11, 2026
Bring in main's runtime.rs mesh acp_model wire translation so local
checks and CI both run on the merged tree. Clean auto-merge; the PR's
fail-closed spawn gating and main's model translation touch disjoint
regions of spawn_agent_child.

* origin/main: (24 commits)
  Improve desktop search scoping (#5306)
  Add glass appearance and cohesive settings (#5478)
  Add Send to channel for thread messages (#5305)
  Fix macOS attachment picker lifecycle and allow inert HTML downloads (#5569)
  fix(desktop): preserve fresh channel timelines (#5577)
  fix(desktop): suppress fresh focus-return refetches for channels and home-feed (#5535)
  chore: mesh upgrade, clean up legacy special case code, simplify model selection for mesh (#5289)
  fix(desktop): preserve theme when opening communities (#5266)
  fix(link-preview): resolve YouTube videos through oEmbed (#5520)
  fix(buzz-agent): harden Databricks OAuth token cache and callback (#5534)
  fix(link-preview): reliably render previews sent right after they resolve (#5245)
  fix(link-preview): restore Buzz entity link cards (#5494)
  chore(release): release Buzz Desktop version 0.5.9 (#5521)
  feat(cli): add --visibility flag to channels update (#5119)
  Polish desktop onboarding flow (#5310)
  fix(desktop): quiesce renderer polling while hidden (#3677) (#5490)
  fix(channels): restore member invitations to private channels (#5493)
  perf(ci): experiment with sccache for relay builds (#5224)
  fix(desktop): bound nine unbounded localStorage stores (#5454)
  feat(desktop): time-based sweep for stale localStorage caches (#5453)
  ...

Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
atishpatel pushed a commit that referenced this pull request Aug 12, 2026
…overy

* origin/main:
  Add glass appearance and cohesive settings (#5478)
  Add Send to channel for thread messages (#5305)
  Fix macOS attachment picker lifecycle and allow inert HTML downloads (#5569)
  fix(desktop): preserve fresh channel timelines (#5577)
  fix(desktop): suppress fresh focus-return refetches for channels and home-feed (#5535)
  chore: mesh upgrade, clean up legacy special case code, simplify model selection for mesh (#5289)
  fix(desktop): preserve theme when opening communities (#5266)
  fix(link-preview): resolve YouTube videos through oEmbed (#5520)
  fix(buzz-agent): harden Databricks OAuth token cache and callback (#5534)

Signed-off-by: Hardworking Honey <c5c455215c2506cb8ba776518cec804af62d3a0526e32d496a22072e395042b9@buzz.block.builderlab.xyz>
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.

2 participants