diff --git a/SVSim.EmulatedEntrypoint/Matching/BotRoster.cs b/SVSim.EmulatedEntrypoint/Matching/BotRoster.cs
index 486f08e..9fa7ed0 100644
--- a/SVSim.EmulatedEntrypoint/Matching/BotRoster.cs
+++ b/SVSim.EmulatedEntrypoint/Matching/BotRoster.cs
@@ -3,10 +3,13 @@ using SVSim.BattleNode.Bridge;
namespace SVSim.EmulatedEntrypoint.Matching;
///
-/// Phase 3 hardcoded fixture: one stub bot per class (1..8). ai_id
-/// values 4001..4008 are placeholders per the existing
-/// docs/api-spec/endpoints/post-login/rank-battle/ai-start.md TODO —
-/// no live capture exists to validate the real prod catalog.
+/// Phase 3 hardcoded fixture: one stub bot per class (1..8). ai_id values are
+/// the "series 1" tier from the client's rm_ai_setting.csv master table
+/// (1111=Forest, 1121=Sword, … 1181=Portal). The client's
+/// RankMatchAISettingList.GetSettingData(aiId) calls .First(...) against
+/// this table and throws InvalidOperationException if the id is absent — so the
+/// ids MUST match. See data_dumps/client-assets/rm_ai_setting.csv for the full
+/// catalog (32 rows: classes 1-8 × tiers 1-2 × deck variants 1-2).
///
public sealed class BotRoster : IBotRoster
{
@@ -16,28 +19,28 @@ public sealed class BotRoster : IBotRoster
// sleeveId/emblemId/etc returned here.
private static readonly IReadOnlyList Roster = new[]
{
- new AIBotProfile(AiId: 4001, CountryCode: "NONE", UserName: "Forestcraft AI",
+ new AIBotProfile(AiId: 1111, CountryCode: "NONE", UserName: "Forestcraft AI",
SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0,
ClassId: 1, CharaId: 1, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0),
- new AIBotProfile(AiId: 4002, CountryCode: "NONE", UserName: "Swordcraft AI",
+ new AIBotProfile(AiId: 1121, CountryCode: "NONE", UserName: "Swordcraft AI",
SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0,
ClassId: 2, CharaId: 2, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0),
- new AIBotProfile(AiId: 4003, CountryCode: "NONE", UserName: "Runecraft AI",
+ new AIBotProfile(AiId: 1131, CountryCode: "NONE", UserName: "Runecraft AI",
SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0,
ClassId: 3, CharaId: 3, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0),
- new AIBotProfile(AiId: 4004, CountryCode: "NONE", UserName: "Dragoncraft AI",
+ new AIBotProfile(AiId: 1141, CountryCode: "NONE", UserName: "Dragoncraft AI",
SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0,
ClassId: 4, CharaId: 4, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0),
- new AIBotProfile(AiId: 4005, CountryCode: "NONE", UserName: "Shadowcraft AI",
+ new AIBotProfile(AiId: 1151, CountryCode: "NONE", UserName: "Shadowcraft AI",
SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0,
ClassId: 5, CharaId: 5, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0),
- new AIBotProfile(AiId: 4006, CountryCode: "NONE", UserName: "Bloodcraft AI",
+ new AIBotProfile(AiId: 1161, CountryCode: "NONE", UserName: "Bloodcraft AI",
SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0,
ClassId: 6, CharaId: 6, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0),
- new AIBotProfile(AiId: 4007, CountryCode: "NONE", UserName: "Havencraft AI",
+ new AIBotProfile(AiId: 1171, CountryCode: "NONE", UserName: "Havencraft AI",
SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0,
ClassId: 7, CharaId: 7, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0),
- new AIBotProfile(AiId: 4008, CountryCode: "NONE", UserName: "Portalcraft AI",
+ new AIBotProfile(AiId: 1181, CountryCode: "NONE", UserName: "Portalcraft AI",
SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0,
ClassId: 8, CharaId: 8, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0),
};
diff --git a/SVSim.UnitTests/Matching/BotRosterTests.cs b/SVSim.UnitTests/Matching/BotRosterTests.cs
index 7efee8d..9043595 100644
--- a/SVSim.UnitTests/Matching/BotRosterTests.cs
+++ b/SVSim.UnitTests/Matching/BotRosterTests.cs
@@ -14,12 +14,15 @@ public class BotRosterTests
EmblemId: "0", DegreeId: "0", FieldId: 0, IsOfficial: 0, BattleType: 11);
[Test]
- public void Pick_returns_a_bot_with_valid_ai_id()
+ public void Pick_returns_a_bot_with_valid_ai_id_from_rm_ai_setting()
{
var roster = new BotRoster();
var bot = roster.Pick(Ctx("PlayerA", "1"));
- Assert.That(bot.AiId, Is.InRange(4001, 4008));
+ // Series-1 enemy_ai_id values from data_dumps/client-assets/rm_ai_setting.csv —
+ // one per class (1=Forest, 2=Sword, 3=Rune, 4=Dragon, 5=Shadow, 6=Blood, 7=Haven, 8=Portal).
+ // Must match a real row or the client's RankMatchAISettingList.GetSettingData() throws.
+ Assert.That(bot.AiId, Is.AnyOf(1111, 1121, 1131, 1141, 1151, 1161, 1171, 1181));
}
[Test]