Vote Rewards: dedupe provider list on load + idx-aware Vue key#52
Closed
AdaInTheLab wants to merge 1 commit into
Closed
Vote Rewards: dedupe provider list on load + idx-aware Vue key#52AdaInTheLab wants to merge 1 commit into
AdaInTheLab wants to merge 1 commit into
Conversation
PR #50 prevented new duplicates forming (the Newtonsoft-append bug), but admins whose state was poisoned while that bug was active still carry the doubled list in their persisted JSON. Symptoms after loading: - /vote prints "<key>: provider disabled" + "<displayname>: granted ..." side by side because the foreach iterates both entries - Settings tab shows two provider blocks; Vue's v-for warns about duplicate :key values and the diffing reconciles unpredictably Two-part fix: 1. EnsureDefaultProviders now deduplicates by Key on every load. The entry with the strongest "configured" signal wins (enabled+apiKey > enabled > apiKey > anything else), so a real config never gets displaced by an empty stub. Logs a one-line note when it dropped any rows so admins can see it ran. 2. SettingsView.vue's v-for key is now `${provider.key}-${idx}` so duplicate provider keys can't collide in Vue's diffing. Defense in depth — the backend dedup means duplicates shouldn't reach the UI anymore, but the v-for shouldn't be the thing that breaks if they do. Self-heals existing poisoned state on the next server boot. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7 tasks
Collaborator
Author
|
Superseded by #53 (which carries the same dedup commit + adds 2-col layout). Closing in favor of the unified PR. |
AdaInTheLab
added a commit
that referenced
this pull request
Apr 30, 2026
* Vote Rewards: dedupe provider list on load, idx-aware Vue key PR #50 prevented new duplicates forming (the Newtonsoft-append bug), but admins whose state was poisoned while that bug was active still carry the doubled list in their persisted JSON. Symptoms after loading: - /vote prints "<key>: provider disabled" + "<displayname>: granted ..." side by side because the foreach iterates both entries - Settings tab shows two provider blocks; Vue's v-for warns about duplicate :key values and the diffing reconciles unpredictably Two-part fix: 1. EnsureDefaultProviders now deduplicates by Key on every load. The entry with the strongest "configured" signal wins (enabled+apiKey > enabled > apiKey > anything else), so a real config never gets displaced by an empty stub. Logs a one-line note when it dropped any rows so admins can see it ran. 2. SettingsView.vue's v-for key is now `${provider.key}-${idx}` so duplicate provider keys can't collide in Vue's diffing. Defense in depth — the backend dedup means duplicates shouldn't reach the UI anymore, but the v-for shouldn't be the thing that breaks if they do. Self-heals existing poisoned state on the next server boot. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Vote Rewards: 2-col tab layout (config left, audit right) The Vote Rewards tab was rendering everything in a single column inside the left half of the available width — large empty space sat to the right. Mirrors the Discord tab pattern: a 2-col grid at the tab level, with the configuration cards (master toggle, providers, save) on the left and the audit feed on the right. Grid is 3fr / 2fr because the provider config card is wider than the audit table needs. Collapses to single column at <=1100px (earlier than the 768px tablet breakpoint) since the 3:2 split gets cramped on narrow-desktop screens before mobile. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PR #50 prevented new duplicate provider entries from forming (the Newtonsoft-append bug). But admins whose settings JSON got poisoned while that bug was active still carry the doubled list in their persisted state — the deserializer faithfully restores both entries every boot.
Visible symptoms (Ada's test box right now):
Fix
1. `EnsureDefaultProviders` dedups by Key on every load. The entry with the strongest "configured" signal wins:
```
enabled + has-api-key > enabled-only > has-api-key > anything
```
A real config never gets displaced by an empty stub. Logs a single line when it dropped any rows so admins can see it ran.
2. Vue `:key` is now `${provider.key}-${idx}`. Defense in depth — the backend dedup means duplicates shouldn't reach the UI anymore, but the v-for shouldn't be the thing that breaks if they do.
Self-heals
No manual cleanup needed. Restart the server, watch for `VoteRewards: deduped 1 duplicate provider entry/entries on load.` in the log, refresh the panel — single provider block with your real config preserved.
Files
Test plan
🤖 Generated with Claude Code