From 63ce3efb749606e62e08587be870424585f4d06f Mon Sep 17 00:00:00 2001 From: Phillip Tarrant Date: Thu, 9 Jul 2026 15:03:18 -0500 Subject: [PATCH] fix(client): reject empty player name in NewGame.construct (contract minLength:1) Whole-branch review flagged that NewGame.construct validated class and origin refs but not player.name. The canon-log schema requires player.name with minLength:1, so a missing/blank name previously returned ok:true and produced a log the API would reject with 422. Co-Authored-By: Claude Opus 4.8 (1M context) --- client/scripts/newgame/new_game.gd | 3 +++ client/tests/unit/test_new_game.gd | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/client/scripts/newgame/new_game.gd b/client/scripts/newgame/new_game.gd index 6ed2cac..c06b196 100644 --- a/client/scripts/newgame/new_game.gd +++ b/client/scripts/newgame/new_game.gd @@ -19,6 +19,9 @@ static func construct(origin: Dictionary, world: ContentDB, creation: Dictionary if class_id not in allowed: errors.append("class not allowed by origin: %s" % class_id) + if creation.get("name", "").strip_edges() == "": + errors.append("player name is required") + if not errors.is_empty(): return {"ok": false, "errors": errors, "log": null, "state": null} diff --git a/client/tests/unit/test_new_game.gd b/client/tests/unit/test_new_game.gd index 8e62dee..b529b1f 100644 --- a/client/tests/unit/test_new_game.gd +++ b/client/tests/unit/test_new_game.gd @@ -87,6 +87,18 @@ func test_unresolved_origin_is_rejected(): assert_true("unresolved ref: location:nowhere" in res["errors"]) +func test_empty_name_is_rejected(): + var missing_name := _build({"class_id": "sellsword"}) + assert_false(missing_name["ok"]) + assert_true(missing_name["errors"].size() > 0) + assert_null(missing_name["log"]) + + var whitespace_name := _build({"name": " ", "class_id": "sellsword"}) + assert_false(whitespace_name["ok"]) + assert_true(whitespace_name["errors"].size() > 0) + assert_null(whitespace_name["log"]) + + func test_non_companion_override_goes_to_state_not_log(): world.npcs["oda_fenn"] = {"id": "oda_fenn", "name": "Oda Fenn", "role": "npc"} var o := _deserter()