From 4d4eb38fa8093b342b4266c0b339613d1c097681 Mon Sep 17 00:00:00 2001 From: silentgeckoaudit3801 Date: Thu, 23 Jul 2026 13:16:30 -0600 Subject: [PATCH] fix: apply bulk score deltas in correct direction --- .../__tests__/scoresService-additions.test.ts | 11 ++++++++++- backend/src/services/scoresService.ts | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/backend/src/services/__tests__/scoresService-additions.test.ts b/backend/src/services/__tests__/scoresService-additions.test.ts index 021dfdf0..15c23480 100644 --- a/backend/src/services/__tests__/scoresService-additions.test.ts +++ b/backend/src/services/__tests__/scoresService-additions.test.ts @@ -82,7 +82,16 @@ describe('updateUserScoresBulk clamping', () => { const [sql] = mockQuery.mock.calls[0] as [string, unknown[]]; expect(sql).toContain('LEAST(850, GREATEST(300,'); }); -}); + + it('applies positive deltas as score increases in bulk upserts', async () => { + await updateUserScoresBulk(new Map([['user_reward', 25]])); + + const [sql, params] = mockQuery.mock.calls[0] as [string, unknown[]]; + expect(params).toEqual(['user_reward', 25]); + expect(sql).toContain('500 + $2'); + expect(sql).toContain('scores.current_score + EXCLUDED.current_score - 500'); + expect(sql).not.toContain('500 - $2'); + });}); describe('setAbsoluteUserScoresBulk', () => { it('is a noop for empty map', async () => { diff --git a/backend/src/services/scoresService.ts b/backend/src/services/scoresService.ts index c93a268a..1fd6061b 100644 --- a/backend/src/services/scoresService.ts +++ b/backend/src/services/scoresService.ts @@ -33,7 +33,7 @@ export async function updateUserScoresBulk( // Clamped the initial raw value payload insertion step to prevent violating constraints on initial inserts const valuePlaceholders = Array.from( { length: params.length / 2 }, - (_, i) => `($${i * 2 + 1}, LEAST(850, GREATEST(300, 500 - $${i * 2 + 2})))`, + (_, i) => `($${i * 2 + 1}, LEAST(850, GREATEST(300, 500 + $${i * 2 + 2})))`, ).join(', '); const sql = `