namespace NeonSprawl.Server.Game.Factions; /// /// Orchestrates auditable faction standing apply: standing mutation + append-only audit row (NEO-136). /// Quest reward wiring: (NEO-138). /// NEO-141 telemetry hook site: successful apply path in . /// public static class ReputationOperations { /// /// Applies a signed standing delta for one player+faction, clamps to faction bounds, and appends one audit row. /// Callers must not invoke alone for game apply. /// public static ReputationApplyOutcome TryApplyDelta( string playerId, string factionId, int deltaAmount, string deltaId, string sourceKind, string sourceId, IFactionStandingStore standingStore, IReputationDeltaStore auditStore, TimeProvider timeProvider) { if (deltaAmount == 0) { return Deny(ReputationApplyReasonCodes.InvalidDelta); } var normalizedPlayerId = FactionStandingIds.NormalizePlayerId(playerId); var normalizedFactionId = FactionStandingIds.NormalizeFactionId(factionId); var normalizedDeltaId = deltaId.Trim(); if (normalizedDeltaId.Length == 0) { return Deny(ReputationApplyReasonCodes.InvalidDeltaId); } var normalizedSourceKind = sourceKind.Trim(); var normalizedSourceId = sourceId.Trim(); if (normalizedSourceKind.Length == 0 || normalizedSourceId.Length == 0) { return Deny(ReputationApplyReasonCodes.InvalidSource); } var mutation = standingStore.TryApplyStandingDelta(normalizedPlayerId, normalizedFactionId, deltaAmount); if (!mutation.Success) { return new ReputationApplyOutcome( false, mutation.ReasonCode, mutation.PreviousStanding, mutation.NewStanding, null); } var appliedDelta = mutation.NewStanding - mutation.PreviousStanding; var row = new ReputationDeltaRow( normalizedDeltaId, normalizedPlayerId, normalizedFactionId, appliedDelta, mutation.NewStanding, normalizedSourceKind, normalizedSourceId, timeProvider.GetUtcNow()); if (auditStore.TryAppend(row)) { // --- Telemetry hook site (NEO-141): future E9.M1 catalog event `reputation_delta` --- return new ReputationApplyOutcome( true, null, mutation.PreviousStanding, mutation.NewStanding, row); } if (appliedDelta != 0) { _ = standingStore.TryApplyStandingDelta(normalizedPlayerId, normalizedFactionId, -appliedDelta); } return new ReputationApplyOutcome( false, ReputationApplyReasonCodes.AuditAppendFailed, mutation.PreviousStanding, mutation.PreviousStanding, null); } private static ReputationApplyOutcome Deny(string reasonCode) => new(false, reasonCode, 0, 0, null); }