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:
@@ -95,7 +95,7 @@ public class ArenaTwoPickBattleControllerTests
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task DoMatching_two_concurrent_pollers_both_return_3004_with_same_BattleId()
|
||||
public async Task DoMatching_two_pollers_get_3004_joiner_and_3007_owner_with_same_BattleId()
|
||||
{
|
||||
using var factory = new SVSimTestFactory();
|
||||
var vidA = await factory.SeedViewerAsync(steamId: 76_561_198_000_000_011UL);
|
||||
@@ -116,20 +116,24 @@ public class ArenaTwoPickBattleControllerTests
|
||||
Assert.That(docA1.RootElement.GetProperty("matching_state").GetInt32(), Is.EqualTo(3002),
|
||||
"A's first poll parks (3002 = RETRY).");
|
||||
|
||||
// B polls (pairs).
|
||||
// B polls and triggers the pair — B is the JOINER (3004).
|
||||
var respB = await clientB.PostAsync("/arena_two_pick_battle/do_matching", JsonContent.Create(req));
|
||||
using var docB = JsonDocument.Parse(await respB.Content.ReadAsStringAsync());
|
||||
Assert.That(docB.RootElement.GetProperty("matching_state").GetInt32(), Is.EqualTo(3004),
|
||||
"B's poll pairs with A.");
|
||||
"B (second arriver, triggered the pair) is the joiner — wire matching_state 3004.");
|
||||
var bBattleId = docB.RootElement.GetProperty("battle_id").GetString();
|
||||
Assert.That(bBattleId, Is.Not.Null.And.Not.Empty);
|
||||
|
||||
// A polls again, picks up the cached result.
|
||||
// A polls again, picks up the cached pair — A is the OWNER (3007).
|
||||
var respA2 = await clientA.PostAsync("/arena_two_pick_battle/do_matching", JsonContent.Create(req));
|
||||
using var docA2 = JsonDocument.Parse(await respA2.Content.ReadAsStringAsync());
|
||||
Assert.That(docA2.RootElement.GetProperty("matching_state").GetInt32(), Is.EqualTo(3004),
|
||||
"A's second poll picks up the cached match.");
|
||||
Assert.That(docA2.RootElement.GetProperty("battle_id").GetString(), Is.EqualTo(bBattleId));
|
||||
Assert.That(docA2.RootElement.GetProperty("matching_state").GetInt32(), Is.EqualTo(3007),
|
||||
"A (first arriver, picked up cached pair) is the owner — wire matching_state 3007.");
|
||||
Assert.That(docA2.RootElement.GetProperty("battle_id").GetString(), Is.EqualTo(bBattleId),
|
||||
"Owner and joiner must see the same battle_id.");
|
||||
Assert.That(docA2.RootElement.GetProperty("node_server_url").GetString(),
|
||||
Is.EqualTo(docB.RootElement.GetProperty("node_server_url").GetString()),
|
||||
"Owner and joiner must see the same node_server_url.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
Reference in New Issue
Block a user