feat(arena-tk2): split do_matching success into 3007 owner / 3004 joiner

Mirrors prod's TK2 wire flow: the first arriver (parked, picks up cached
pair on a later poll) gets matching_state 3007 (SUCCEEDED_OWNER); the
second arriver (whose poll triggered the pair) gets 3004 (SUCCEEDED).

Observationally inert in the public matching code path today — the
client's Matching class writes isOwner from the response into a field
that nothing in TK2/ranked reads. Matching_Room (private rooms) DOES
read it but from a separate code path that doesn't consult our response.
We send the split anyway for prod fidelity and to leave room for future
flows (rematch UI, etc.) that might start consuming it.

TryPairAsync now returns PairUpResult(Match, IsOwner) instead of bare
PendingMatch?, so the controller can decide owner vs joiner without
re-deriving it.

Also documents on DoMatchingResponseDto why we omit prod's `room_id`
field (not in the client's DoMatchingDetail model; private-room flows
get their room id from a different API and don't consult this response).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-06-01 23:24:13 -04:00
parent 0ecd565774
commit 8112b3f81f
6 changed files with 72 additions and 24 deletions

View File

@@ -4,6 +4,21 @@ using SVSim.EmulatedEntrypoint.Models.Dtos.Common;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Responses.ArenaTwoPick;
/// <remarks>
/// Wire-shape notes vs prod do_matching captures (2026-05-31 TK2 capture):
/// <list type="bullet">
/// <item>Prod sends <c>room_id</c> from matching_state 3003 onward. We deliberately
/// omit it. The client's <c>DoMatchingDetail</c> data model has no <c>room_id</c>
/// field and <c>DoMatchingBase.SettingDoMatchingData()</c> never reads the key;
/// private-room flows (<c>RoomConnectController</c>) get their room id from a
/// separate API (<c>OpenRoomBattleCreate*</c>) and don't consult this response.
/// Re-add only if a downstream consumer surfaces.</item>
/// <item><c>node_server_url</c> must always be present (empty string while waiting,
/// actual URL on SUCCEEDED/SUCCEEDED_OWNER). The client's accessor is unguarded.</item>
/// <item><c>battle_id</c> stays absent on RETRY (its accessor IS guarded via
/// <c>Keys.Contains</c>).</item>
/// </list>
/// </remarks>
[MessagePackObject]
public sealed class DoMatchingResponseDto
{