From 94acf57e5bdf786d1d7cf429a29aef0989877436 Mon Sep 17 00:00:00 2001 From: VinPropane Date: Mon, 15 Jun 2026 20:35:24 -0400 Subject: [PATCH] NEO-135: apply standing deltas from clamped effective value Compute newStanding from previousStanding + deltaAmount so stale out-of-band persisted values match TryGetStanding before mutation. --- .../InMemoryFactionStandingStoreTests.cs | 16 ++++++++++++++++ .../Factions/InMemoryFactionStandingStore.cs | 2 +- .../Factions/PostgresFactionStandingStore.cs | 2 +- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/server/NeonSprawl.Server.Tests/Game/Factions/InMemoryFactionStandingStoreTests.cs b/server/NeonSprawl.Server.Tests/Game/Factions/InMemoryFactionStandingStoreTests.cs index bf11902..1afc3ca 100644 --- a/server/NeonSprawl.Server.Tests/Game/Factions/InMemoryFactionStandingStoreTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Factions/InMemoryFactionStandingStoreTests.cs @@ -118,6 +118,22 @@ public sealed class InMemoryFactionStandingStoreTests Assert.Equal(0, store.TryGetStanding(PlayerId, GridFactionId).Standing); } + [Fact] + public void TryApplyStandingDelta_ShouldApplyToClampedEffectiveStanding_WhenRawStoredValueExceedsMax() + { + // Arrange + var store = CreateStore(); + store.SeedRawStandingForTests(PlayerId, GridFactionId, 999); + Assert.Equal(100, store.TryGetStanding(PlayerId, GridFactionId).Standing); + // Act + var outcome = store.TryApplyStandingDelta(PlayerId, GridFactionId, -15); + // Assert + Assert.True(outcome.Success); + Assert.Equal(100, outcome.PreviousStanding); + Assert.Equal(85, outcome.NewStanding); + Assert.Equal(85, store.TryGetStanding(PlayerId, GridFactionId).Standing); + } + [Fact] public void TryGetStanding_ShouldPreferUnknownFaction_WhenPlayerNotWritableAndFactionUnknown() { diff --git a/server/NeonSprawl.Server/Game/Factions/InMemoryFactionStandingStore.cs b/server/NeonSprawl.Server/Game/Factions/InMemoryFactionStandingStore.cs index 9da80e8..4f814bd 100644 --- a/server/NeonSprawl.Server/Game/Factions/InMemoryFactionStandingStore.cs +++ b/server/NeonSprawl.Server/Game/Factions/InMemoryFactionStandingStore.cs @@ -93,7 +93,7 @@ public sealed class InMemoryFactionStandingStore( { var raw = standingByKey.GetValueOrDefault(key, 0); var previousStanding = FactionStandingIds.ClampStanding(raw, definition); - var newStanding = FactionStandingIds.ClampStanding(raw + deltaAmount, definition); + var newStanding = FactionStandingIds.ClampStanding(previousStanding + deltaAmount, definition); standingByKey[key] = newStanding; return new FactionStandingMutationOutcome(true, null, previousStanding, newStanding); } diff --git a/server/NeonSprawl.Server/Game/Factions/PostgresFactionStandingStore.cs b/server/NeonSprawl.Server/Game/Factions/PostgresFactionStandingStore.cs index 3fe7203..fdb3ffd 100644 --- a/server/NeonSprawl.Server/Game/Factions/PostgresFactionStandingStore.cs +++ b/server/NeonSprawl.Server/Game/Factions/PostgresFactionStandingStore.cs @@ -117,7 +117,7 @@ public sealed class PostgresFactionStandingStore( } var previousStanding = FactionStandingIds.ClampStanding(raw, definition); - var newStanding = FactionStandingIds.ClampStanding(raw + deltaAmount, definition); + var newStanding = FactionStandingIds.ClampStanding(previousStanding + deltaAmount, definition); using var upsert = new Npgsql.NpgsqlCommand( """