Skip to content

Fix like count drift on failed like/unlike mutations#81

Open
vagxrth wants to merge 1 commit into
saiy2k:mainfrom
vagxrth:fix/like-count-drift
Open

Fix like count drift on failed like/unlike mutations#81
vagxrth wants to merge 1 commit into
saiy2k:mainfrom
vagxrth:fix/like-count-drift

Conversation

@vagxrth

@vagxrth vagxrth commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

Closes #78

Summary

This PR fixes the local like-count drift bug in nostr-like-button when like or unlike operations fail.

Previously, the component used unconditional arithmetic rollback in the catch path. That meant failures could push the displayed count in the wrong direction even when an optimistic mutation had not actually been applied.

This PR replaces that with snapshot-based rollback, clamps displayed counts to non-negative values, and adds a coalesced authoritative resync path after failed mutations.

What changed

Optimistic state helpers

Added a small internal helper module:

  • src/nostr-like-button/optimistic-state.ts

It provides:

  • LikeUiState
  • clampLikeCount()
  • applyOptimisticLike()
  • applyOptimisticUnlike()
  • rollbackOptimisticLikeState()

These helpers keep the mutation/rollback behavior explicit and easy to test.

nostr-like rollback and resync behavior

Updated:

  • src/nostr-like-button/nostr-like.ts

Changes include:

  • fetched totals are now clamped before being assigned to the displayed count
  • like/unlike mutation flows now snapshot the pre-mutation UI state
  • optimistic state is applied explicitly via helper functions
  • rollback only restores the snapshot when an optimistic update was actually applied
  • failure-before-optimistic no longer drifts local count
  • failed mutations now queue a best-effort authoritative resync
  • resync requests are coalesced so repeated failures during an in-flight resync still result in a final refresh

Why this fixes the bug

The previous implementation assumed that rollback arithmetic should always run in the error path:

  • failed like: decrement count
  • failed unlike: increment count

That is only valid if the optimistic mutation was already applied.

With this PR:

  • if failure happens before optimistic state is applied, the component preserves the current UI state and only clamps the count
  • if failure happens after optimistic state is applied, the component restores the exact pre-mutation snapshot

This removes count drift and makes failure handling deterministic.

Tests

Added focused regression tests in:

  • src/nostr-like-button/__tests__/optimistic-state.test.ts

Covered cases:

  • clamp negative counts to zero
  • optimistic like increments count and sets liked state
  • optimistic unlike never drops below zero
  • failure-before-optimistic preserves current state and avoids drift
  • failure-after-optimistic restores the original snapshot

Verification

Ran:

  • npm test -- --run
  • npm run build-storybook

@coderabbitai

coderabbitai Bot commented Apr 20, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@vagxrth has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 28 minutes and 28 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 28 minutes and 28 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ea35cdbf-f012-4014-8f98-514b4b181b2a

📥 Commits

Reviewing files that changed from the base of the PR and between dfc22e5 and 924402c.

📒 Files selected for processing (3)
  • src/nostr-like-button/__tests__/optimistic-state.test.ts
  • src/nostr-like-button/nostr-like.ts
  • src/nostr-like-button/optimistic-state.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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.

Bug: optimistic rollback can drift like counts on failed like/unlike operations

1 participant