#nullable enable using Baya.Application.Contracts.Reviews; using Microsoft.Extensions.Options; namespace Baya.Infrastructure.CrossCutting.Seams; /// /// Deterministic mock (b14) — a keyword filter / pass-through with no /// external call. A banned-word hit → ; otherwise clean text → a /// human-review by default (so the publish gate holds), or /// when is set. /// The real text classifier / LLM endpoint swaps in by a registration change only — the moderation command /// keeps decision authority and the human override, so it never touches the handler. /// public sealed class MockReviewModerationService(IOptions options) : IReviewModerationService { private readonly ReviewModerationOptions _options = options.Value.ReviewModeration; public ValueTask ScreenAsync(string? reviewText, CancellationToken cancellationToken = default) { var text = reviewText?.Trim() ?? string.Empty; var hit = _options.BannedWords.FirstOrDefault( w => !string.IsNullOrWhiteSpace(w) && text.Contains(w, StringComparison.OrdinalIgnoreCase)); if (hit is not null) return ValueTask.FromResult(new ModerationVerdict(ModerationDecision.Reject, $"banned_word:{hit}")); var decision = _options.AutoApproveClean ? ModerationDecision.Approve : ModerationDecision.Flag; return ValueTask.FromResult(new ModerationVerdict(decision, "clean")); } }