feat(guild): leave + remove with leader-leaves rule

- LeaveAsync: regular/subleader removes self; leader blocked if members remain;
  sole-member leader auto-routes to BreakupAsync.
- RemoveAsync: leader-only kick (SubLeader has no remove authority per
  GuildManager.cs decompile); self-remove and cross-guild target rejected.
- GuildController: wired /guild/leave (BaseRequest) and /guild/remove
  (GuildRemoveRequest.remove_viewer_id field).
- SpyGuildChatService: extended Emissions with EmissionsWithBody tuple to
  allow body-content assertions in leave/remove tests.
- 8 new integration tests; all 1493 pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-06-27 14:16:47 -04:00
parent 901c3d7568
commit 00fb28681b
4 changed files with 391 additions and 6 deletions

View File

@@ -14,10 +14,12 @@ namespace SVSim.UnitTests.Services.Guild;
internal sealed class SpyGuildChatService : IGuildChatService
{
public readonly List<(int GuildId, long ActorId, GuildChatMessageType Type)> Emissions = new();
public readonly List<(int GuildId, long ActorId, GuildChatMessageType Type, string? Body)> EmissionsWithBody = new();
public Task EmitSystemEventAsync(int guildId, long actorViewerId, GuildChatMessageType type, string? body = null, CancellationToken ct = default)
{
Emissions.Add((guildId, actorViewerId, type));
EmissionsWithBody.Add((guildId, actorViewerId, type, body));
return Task.CompletedTask;
}