Skip to content

feat(emoji): latest-set-wins union for custom emoji across desktop, mobile, and CLI#989

Merged
tlongwell-block merged 3 commits into
mainfrom
eva/emoji-latest-wins
Jun 13, 2026
Merged

feat(emoji): latest-set-wins union for custom emoji across desktop, mobile, and CLI#989
tlongwell-block merged 3 commits into
mainfrom
eva/emoji-latest-wins

Conversation

@tlongwell-block

@tlongwell-block tlongwell-block commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

Switch the custom-emoji union from "lexicographically-smallest URL wins" to latest-set-wins across all three clients:

  • Desktop (desktop/src/shared/api/customEmoji.ts): unionCustomEmoji() now tracks (url, created_at) per shortcode and prefers the most recently published set, tie-breaking equal timestamps to the smallest URL.
  • Mobile (mobile/lib/features/custom_emoji/custom_emoji.dart, one Dart codebase covering iOS + Android): same rule.
  • CLI (crates/buzz-cli/src/commands/emoji.rs): same rule. This also fixes a pre-existing divergence — the CLI deduped by (shortcode, url) and could list two URLs for one shortcode; it now collapses to one entry per shortcode like the other clients.

Why

The old rule made shortcode collisions resolve arbitrarily (whichever URL sorts smaller) and meant a member re-publishing their set could never reclaim a contested shortcode. With latest-wins, the most recent signed event owns the shortcode — which is what you'd expect, and what makes the sprout:buzz: emoji-tag cutover clean: a bulk republished union set is automatically superseded per-shortcode whenever an original owner edits their own set.

Determinism is preserved: created_at is part of the signed event, not fetch order, so the same set of events always yields the same palette. The smallest-URL rule survives as the tie-break for equal timestamps (second resolution — ties are realistic).

Verification

  • Desktop: npm test — 628/628, typecheck clean
  • Mobile: flutter test — 384 passing, dart analyze clean
  • CLI: cargo test -p buzz-cli — 117 passing, cargo clippy -- -D warnings and fmt --check clean
  • New tests in each client: newer-set-wins (order-independent) and equal-timestamp tie-break

npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d and others added 3 commits June 11, 2026 15:44
…obile, and CLI

When members claim the same shortcode, the workspace palette now prefers
the most recently published kind:30030 set (created_at desc), tie-breaking
equal timestamps to the lexicographically-smallest URL. created_at is
signed event data, so the result stays deterministic and independent of
fetch order — the original motivation for smallest-URL-wins.

This also makes ownership recoverable: a member re-publishing their set
reclaims their shortcodes from any older set that carries them.

The CLI union previously deduped by (shortcode, url) and could emit two
URLs for one shortcode; it now matches desktop and mobile exactly:
one entry per shortcode, latest wins, sorted by shortcode.

Co-authored-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@sprout-oss.stage.blox.sqprod.co>
* origin/main: (33 commits)
  fix(desktop): make Windows release compile cleanly (#1029)
  Add production Docker Compose bundle (#985)
  feat(profile): show active turn badges on agent profile panel and popover (#1026)
  chore(release): release version 0.3.20 (#1027)
  fix(release): resolve Windows sidecar path and Linux AppImage updater format (#1024)
  chore(release): release version 0.3.19 (#1014)
  fix(release): ignore prerelease tags in changelog generation (#1021)
  fix: repair main build after cross-PR merge skew (#1020)
  feat(agents): show per-turn duration and prune dead turns within ~25s of host crash (#1017)
  fix(release): replace hermit with native tool setup on Windows job (#1018)
  feat(acp): surface error-class outcomes to the activity feed only, never the channel (#1010)
  fix(desktop): migrate Sprout workspace storage (#1016)
  feat(auth): force token refresh on rejected token (401/403), never the browser (#1015)
  fix(release): mark prerelease versions so they do not become latest (#1013)
  feat(acp): implement systemPrompt with protocol version gating (#981)
  fix(release): update repository name check from block/sprout to block/buzz (#1012)
  feat(release): all-OS desktop builds + universal auto-update manifest (#1011)
  Add relay disconnect UX: friendly errors, reconnect, cached identity (#1004)
  feat(agents): add active turn indicators to Agents Menu (#1005)
  ci: add fork guards to docker, release, and auto-tag workflows (#1007)
  ...

Co-authored-by: npub1t2tgm7d8f995uqvmnm8h88sg3wnpp9a5xysjf6dg3tjmgt3ltulqdp8ehr <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: npub1t2tgm7d8f995uqvmnm8h88sg3wnpp9a5xysjf6dg3tjmgt3ltulqdp8ehr <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@sprout-oss.stage.blox.sqprod.co>
Co-authored-by: npub1t2tgm7d8f995uqvmnm8h88sg3wnpp9a5xysjf6dg3tjmgt3ltulqdp8ehr <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: npub1t2tgm7d8f995uqvmnm8h88sg3wnpp9a5xysjf6dg3tjmgt3ltulqdp8ehr <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@sprout-oss.stage.blox.sqprod.co>
@tlongwell-block tlongwell-block merged commit 6e4c868 into main Jun 13, 2026
27 checks passed
@tlongwell-block tlongwell-block deleted the eva/emoji-latest-wins branch June 13, 2026 17:50
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