diff --git a/SVSim.EmulatedEntrypoint/Matching/IMatchingPairUpService.cs b/SVSim.EmulatedEntrypoint/Matching/IMatchingPairUpService.cs
index ffbadcc..551e4d6 100644
--- a/SVSim.EmulatedEntrypoint/Matching/IMatchingPairUpService.cs
+++ b/SVSim.EmulatedEntrypoint/Matching/IMatchingPairUpService.cs
@@ -34,5 +34,11 @@ public interface IMatchingPairUpService
/// nothing else in TK2/ranked reads. We send the split anyway for prod fidelity in
/// case a future flow (rematch UI, private rooms grafted on top) starts consuming it.
///
+///
+/// is true when the resolution came from the
+/// PvpFirstThenAiFallback policy expiring its threshold — caller is paired
+/// with a silent NoOpBotParticipant. Maps to matching_state 3011
+/// (AI_BATTLE_MATCHING_SUCCEEDED). Always false for PvpOnly modes (TK2).
+///
///
-public sealed record PairUpResult(PendingMatch Match, bool IsOwner);
+public sealed record PairUpResult(PendingMatch Match, bool IsOwner, bool IsAiFallback);
diff --git a/SVSim.EmulatedEntrypoint/Matching/InProcessPairUp.cs b/SVSim.EmulatedEntrypoint/Matching/InProcessPairUp.cs
index 59e2b15..d611ddf 100644
--- a/SVSim.EmulatedEntrypoint/Matching/InProcessPairUp.cs
+++ b/SVSim.EmulatedEntrypoint/Matching/InProcessPairUp.cs
@@ -28,7 +28,7 @@ public sealed class InProcessPairUp : IMatchingPairUpService
if (slot.Resolved.TryGetValue(player.ViewerId, out var cached))
{
slot.Resolved.Remove(player.ViewerId);
- return Task.FromResult(new PairUpResult(cached, IsOwner: true));
+ return Task.FromResult(new PairUpResult(cached, IsOwner: true, IsAiFallback: false));
}
// 2. Someone already waiting in this slot? Pair with them.
@@ -46,7 +46,7 @@ public sealed class InProcessPairUp : IMatchingPairUpService
var match = _bridge.RegisterBattle(p1, p2, BattleType.Pvp);
// Cache the result for the FIRST arriver's next poll (consume-on-read).
slot.Resolved[p1.ViewerId] = match;
- return Task.FromResult(new PairUpResult(match, IsOwner: false));
+ return Task.FromResult(new PairUpResult(match, IsOwner: false, IsAiFallback: false));
}
// 3. Empty slot — park this caller.