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 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(playerId, factionId, deltaAmount); if (!mutation.Success) { return new ReputationApplyOutcome( false, mutation.ReasonCode, mutation.PreviousStanding, mutation.NewStanding, null); } var row = new ReputationDeltaRow( normalizedDeltaId, playerId, factionId, deltaAmount, 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); } _ = standingStore.TryApplyStandingDelta(playerId, factionId, -deltaAmount); return new ReputationApplyOutcome( false, ReputationApplyReasonCodes.AuditAppendFailed, mutation.PreviousStanding, mutation.PreviousStanding, null); } private static ReputationApplyOutcome Deny(string reasonCode) => new(false, reasonCode, 0, 0, null); }