From a4171742c5ba30b779d7f05acfbe9f7061a0e1cd Mon Sep 17 00:00:00 2001 From: Ada Date: Thu, 30 Apr 2026 12:48:05 -0400 Subject: [PATCH] Vote Rewards: dedupe provider list on load, idx-aware Vue key MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 ": provider disabled" + ": 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) --- frontend/src/views/SettingsView.vue | 5 +++- .../Features/VoteRewardsFeature.cs | 24 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/frontend/src/views/SettingsView.vue b/frontend/src/views/SettingsView.vue index 2c991b3..47a38dd 100644 --- a/frontend/src/views/SettingsView.vue +++ b/frontend/src/views/SettingsView.vue @@ -1342,7 +1342,10 @@ onMounted(() => {