diff --git a/SVSim.EmulatedEntrypoint/Controllers/PackController.cs b/SVSim.EmulatedEntrypoint/Controllers/PackController.cs
index 26496ff..ed27392 100644
--- a/SVSim.EmulatedEntrypoint/Controllers/PackController.cs
+++ b/SVSim.EmulatedEntrypoint/Controllers/PackController.cs
@@ -14,8 +14,8 @@ using SVSim.EmulatedEntrypoint.Services;
namespace SVSim.EmulatedEntrypoint.Controllers;
///
-/// /pack/* — card-pack shop catalog and pack opening. Tutorial aliases (/tutorial/pack_info,
-/// /tutorial/pack_open) are out of scope for v1.
+/// /pack/* — card-pack shop catalog and pack opening. /tutorial/pack_info is aliased here.
+/// /tutorial/pack_open is out of scope for v1.
///
[Route("pack")]
public class PackController : SVSimController
@@ -46,6 +46,7 @@ public class PackController : SVSimController
}
[HttpPost("info")]
+ [HttpPost("/tutorial/pack_info")]
public async Task> Info(BaseRequest request)
{
if (!TryGetViewerId(out long viewerId)) return Unauthorized();
diff --git a/SVSim.UnitTests/Controllers/PackControllerTests.cs b/SVSim.UnitTests/Controllers/PackControllerTests.cs
new file mode 100644
index 0000000..8dc6c2b
--- /dev/null
+++ b/SVSim.UnitTests/Controllers/PackControllerTests.cs
@@ -0,0 +1,29 @@
+using System.Net;
+using System.Text;
+using SVSim.UnitTests.Infrastructure;
+
+namespace SVSim.UnitTests.Controllers;
+
+public class PackControllerTests
+{
+ [Test]
+ public async Task TutorialPackInfo_returns_same_list_as_pack_info()
+ {
+ using var factory = new SVSimTestFactory();
+ await factory.SeedGlobalsAsync();
+ long viewerId = await factory.SeedViewerAsync(tutorialState: 41);
+ using var client = factory.CreateAuthenticatedClient(viewerId);
+
+ var json = """{"viewer_id":"0","steam_id":0,"steam_session_ticket":""}""";
+ var direct = await client.PostAsync("/pack/info", new StringContent(json, Encoding.UTF8, "application/json"));
+ var tutorial = await client.PostAsync("/tutorial/pack_info", new StringContent(json, Encoding.UTF8, "application/json"));
+
+ Assert.That(direct.StatusCode, Is.EqualTo(HttpStatusCode.OK));
+ Assert.That(tutorial.StatusCode, Is.EqualTo(HttpStatusCode.OK));
+
+ var directBody = await direct.Content.ReadAsStringAsync();
+ var tutorialBody = await tutorial.Content.ReadAsStringAsync();
+ Assert.That(tutorialBody, Is.EqualTo(directBody),
+ "tutorial/pack_info wire shape must match /pack/info exactly (no filtering in v1).");
+ }
+}