diff --git a/public/break_escape/js/minigames/person-chat/person-chat-conversation.js b/public/break_escape/js/minigames/person-chat/person-chat-conversation.js index 0896b39..ac1b019 100644 --- a/public/break_escape/js/minigames/person-chat/person-chat-conversation.js +++ b/public/break_escape/js/minigames/person-chat/person-chat-conversation.js @@ -465,13 +465,14 @@ export default class PersonChatConversation { console.log(`✅ NPC ${this.npc.id} successfully unlocked door ${doorId}`); window.gameAlert(`Door unlocked!`, 'success', 'Access Granted', 3000); - // Trigger door unlock visual update for ALL door sprites leading to this room + // Update door sprite lock state for ALL door sprites leading to this room // This handles the case where the room is already loaded + // Don't open the door - just mark it as unlocked so player can open it const doorSprites = this.findAllDoorSprites(doorId); - if (doorSprites.length > 0 && window.unlockDoor) { + if (doorSprites.length > 0 && window.markDoorUnlocked) { console.log(`📍 Found ${doorSprites.length} door sprite(s) to update`); doorSprites.forEach(doorSprite => { - window.unlockDoor(doorSprite, response.roomData); + window.markDoorUnlocked(doorSprite, response.roomData); }); } else { console.log(`📍 No door sprites found for ${doorId}, will be unlocked when room loads`); diff --git a/public/break_escape/js/systems/doors.js b/public/break_escape/js/systems/doors.js index f1fed17..2931b7e 100644 --- a/public/break_escape/js/systems/doors.js +++ b/public/break_escape/js/systems/doors.js @@ -597,8 +597,28 @@ function unlockDoor(doorSprite, roomData) { openDoor(doorSprite); } -// Make unlockDoor globally available for NPC unlock handlers +// Function to mark a door as unlocked without opening it +// Used by NPC unlocks where we want to update the sprite state but not open the door +function markDoorUnlocked(doorSprite, roomData) { + const props = doorSprite.doorProperties; + console.log(`Marking door as unlocked: ${props.roomId} -> ${props.connectedRoom}`); + + // Mark door as unlocked + props.locked = false; + + // If roomData was provided from server unlock response, cache it + if (roomData && window.roomDataCache) { + console.log(`📦 Caching room data for ${props.connectedRoom} from unlock response`); + window.roomDataCache.set(props.connectedRoom, roomData); + } + + // Don't open the door - just update the visual state if needed + // TODO: Add visual indicator that door is now unlocked (e.g., change tint, add icon) +} + +// Make both functions globally available window.unlockDoor = unlockDoor; +window.markDoorUnlocked = markDoorUnlocked; // Function to open a door function openDoor(doorSprite) { @@ -1263,4 +1283,4 @@ window.processAllDoorCollisions = processAllDoorCollisions; window.handleDoorInteraction = handleDoorInteraction; // Export functions for use by other modules -export { unlockDoor, handleDoorInteraction }; +export { unlockDoor, markDoorUnlocked, handleDoorInteraction }; diff --git a/test/dummy/log/test.log b/test/dummy/log/test.log index bd553e2..7087ff6 100644 --- a/test/dummy/log/test.log +++ b/test/dummy/log/test.log @@ -29366,5 +29366,931 @@ Processing by BreakEscape::GamesController#unlock as HTML BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:32:48.566166"], ["id", 1]] TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.1ms) rollback transaction + ActiveRecord::InternalMetadata Load (0.5ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] + ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC + TRANSACTION (0.1ms) begin transaction +  (0.5ms) PRAGMA foreign_keys +  (0.1ms) PRAGMA defer_foreign_keys +  (0.1ms) PRAGMA defer_foreign_keys = ON +  (0.0ms) PRAGMA foreign_keys = OFF + Fixtures Load (0.2ms) DELETE FROM "break_escape_demo_users"; +DELETE FROM "break_escape_missions"; +INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (149617800, 'test_user', '2025-11-22 00:41:05', '2025-11-22 00:41:05'); +INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-22 00:41:05', '2025-11-22 00:41:05'); +INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (418560898, 'ceo_exfil', 'CEO Exfiltration', 'Test scenario', 1, 3, '2025-11-22 00:41:05', '2025-11-22 00:41:05'); +INSERT INTO "break_escape_missions" ("id", "name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at") VALUES (636030761, 'test_unpublished', 'Unpublished Test', 'Not visible', 0, 1, '2025-11-22 00:41:05', '2025-11-22 00:41:05') +  (0.1ms) PRAGMA defer_foreign_keys = 0 +  (0.0ms) PRAGMA foreign_keys = 1 + TRANSACTION (3.8ms) commit transaction +  (0.1ms) PRAGMA foreign_key_check + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_password_lock:_correct_password_should_unlock +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.7ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.121549"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.120616"], ["updated_at", "2025-11-22 00:41:06.120616"]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.7ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.2ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=door, id=office_password, attempt=opensesame, method=password + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_password\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.235492"], ["id", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 36ms (Views: 0.3ms | ActiveRecord: 1.5ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.1ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_password_lock:_case_sensitivity +----------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.262463"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.262259"], ["updated_at", "2025-11-22 00:41:06.262259"]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"OpenSesame", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=door, id=office_password, attempt=OpenSesame, method=password +Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.1ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_incorrect_PIN_should_fail +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.270212"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.270019"], ["updated_at", "2025-11-22 00:41:06.270019"]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=0000, method=pin +[BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 +[BreakEscape] Password validation: required='1234', attempt='0000', result=false +Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.1ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_correct_PIN_should_unlock +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.276724"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.276450"], ["updated_at", "2025-11-22 00:41:06.276450"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin +[BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 +[BreakEscape] Password validation: required='1234', attempt='1234', result=true + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.281304"], ["id", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.1ms) begin transaction +------------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_NPC_can_unlock_door_if_player_has_encountered_them_and_NPC_has_permission +------------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.285241"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.285069"], ["updated_at", "2025-11-22 00:41:06.285069"]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_pin\",\"office_password\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.286675"], ["id", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin +[BreakEscape] NPC unlock validated: helper_npc can unlock office_pin + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.291187"], ["id", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_NPC_unlock_adds_door_to_unlockedRooms +------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.295119"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.294887"], ["updated_at", "2025-11-22 00:41:06.294887"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_pin\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.296601"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin +[BreakEscape] NPC unlock validated: helper_npc can unlock office_pin + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.300891"], ["id", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.1ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_password_lock:_incorrect_password_should_fail +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.5ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.317325"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.305399"], ["updated_at", "2025-11-22 00:41:06.305399"]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"wrongpassword", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=door, id=office_password, attempt=wrongpassword, method=password +Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.3ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.1ms) begin transaction +---------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_already-unlocked_container_accepts_method='unlocked' +---------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.4ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.325782"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.325576"], ["updated_at", "2025-11-22 00:41:06.325576"]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"npc_safe\",\"type\":\"safe1\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9999\",\"contents\":[{\"type\":\"key\",\"id\":\"master_key\",\"takeable\":true}]}],\"npcs\":[{\"id\":\"helper_npc\",\"unlockable\":[\"npc_safe\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.327484"], ["id", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"npc_safe", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} + BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=object, id=npc_safe, attempt=helper_npc, method=npc +[BreakEscape] Found object: id=npc_safe, name=, locked=true, requires=9999 +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=npc_safe +[BreakEscape] NPC unlock validated: helper_npc can unlock npc_safe + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"npc_safe\"],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.332926"], ["id", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"npc_safe", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=object, id=npc_safe, attempt=, method=unlocked +[BreakEscape] Object already unlocked in player state, granting access + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.6ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.8ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.1ms) begin transaction +-------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_locked_container_cannot_be_bypassed_with_method='unlocked' +-------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.340608"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.340445"], ["updated_at", "2025-11-22 00:41:06.340445"]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=, method=unlocked +[BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 +[BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED object: safe_pin +Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.2ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.1ms) begin transaction +------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_unlock_non-existent_door_should_fail +------------------------------------------------------------------------ + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.347474"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.347301"], ["updated_at", "2025-11-22 00:41:06.347301"]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"non_existent_room", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=door, id=non_existent_room, attempt=1234, method=pin +Completed 422 Unprocessable Content in 1ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlock_with_invalid_method_should_fail +-------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.353488"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.353292"], ["updated_at", "2025-11-22 00:41:06.353292"]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"invalid_method", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=invalid_method +Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_NPC_can_unlock_container_if_player_has_encountered_them_and_NPC_has_permission +------------------------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.359619"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.359412"], ["updated_at", "2025-11-22 00:41:06.359412"]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"safe_pin\",\"cabinet_password\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.361039"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=helper_npc, method=npc +[BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=safe_pin +[BreakEscape] NPC unlock validated: helper_npc can unlock safe_pin + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.365314"], ["id", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_unlockable_is_not_an_array +-------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.369028"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.368866"], ["updated_at", "2025-11-22 00:41:06.368866"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":\"office_pin\"}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.370365"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin +[BreakEscape] NPC helper_npc does not have permission to unlock office_pin +Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.1ms) begin transaction +------------------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_doors +------------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.376443"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.376261"], ["updated_at", "2025-11-22 00:41:06.376261"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=door, id=office_unlocked, attempt=, method=unlocked +[BreakEscape] Door is unlocked in scenario data, granting access + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_unlocked\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.389394"], ["id", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 12ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 10.0ms) + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_biometric_lock:_should_trust_client_validation +------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.4ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.7ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.392603"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.392443"], ["updated_at", "2025-11-22 00:41:06.392443"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"scanner_biometric", "attempt"=>nil, "method"=>"biometric", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=object, id=scanner_biometric, attempt=, method=biometric +[BreakEscape] Found object: id=scanner_biometric, name=Biometric Scanner, locked=true, requires=ceo_fingerprint + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"scanner_biometric\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.397328"], ["id", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.1ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_container_with_password_lock:_correct_password_should_unlock +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.400942"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.400789"], ["updated_at", "2025-11-22 00:41:06.400789"]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"secret123", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=secret123, method=password +[BreakEscape] Found object: id=cabinet_password, name=Password Cabinet, locked=true, requires=secret123 +[BreakEscape] Password validation: required='secret123', attempt='secret123', result=true + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"cabinet_password\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.405716"], ["id", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.1ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_locked_door_cannot_be_bypassed_with_method='unlocked' +--------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.409566"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.409395"], ["updated_at", "2025-11-22 00:41:06.409395"]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=door, id=office_pin, attempt=, method=unlocked +[BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED door: office_pin +Completed 422 Unprocessable Content in 1ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.1ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_for_non-existent_NPC +----------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.2ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.5ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.415816"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.415661"], ["updated_at", "2025-11-22 00:41:06.415661"]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.417299"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"fake_npc", "method"=>"npc", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=door, id=office_pin, attempt=fake_npc, method=npc +[BreakEscape] Validating NPC unlock: npc=fake_npc, target=office_pin +[BreakEscape] NPC not found: fake_npc +Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.1ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_already-unlocked_door_accepts_method='unlocked' +----------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.422963"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.422785"], ["updated_at", "2025-11-22 00:41:06.422785"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"unlockable\":[\"ceo\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]},\"ceo\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"TopSecret123\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.424403"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"ceo", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=door, id=ceo, attempt=helper_npc, method=npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=ceo +[BreakEscape] NPC unlock validated: helper_npc can unlock ceo + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"ceo\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.428557"], ["id", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"ceo", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=door, id=ceo, attempt=, method=unlocked +[BreakEscape] Door already unlocked in player state, granting access + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.5ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.1ms) begin transaction +-------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_unlock_response_should_filter_requires_from_contents +-------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.435721"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.435565"], ["updated_at", "2025-11-22 00:41:06.435565"]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin +[BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 +[BreakEscape] Password validation: required='1234', attempt='1234', result=true + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.441884"], ["id", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.1ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_incorrect_PIN_should_fail +--------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.451643"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.445587"], ["updated_at", "2025-11-22 00:41:06.445587"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=door, id=office_pin, attempt=0000, method=pin +Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.1ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_lockpick:_should_trust_client_validation +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.459034"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.458838"], ["updated_at", "2025-11-22 00:41:06.458838"]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"box_lockpick", "attempt"=>nil, "method"=>"lockpick", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=object, id=box_lockpick, attempt=, method=lockpick +[BreakEscape] Found object: id=box_lockpick, name=Lockpickable Box, locked=true, requires= + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.5ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"box_lockpick\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.463960"], ["id", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.9ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.1ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_password_lock:_empty_attempt_should_fail +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.467487"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.467315"], ["updated_at", "2025-11-22 00:41:06.467315"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=object, id=cabinet_password, attempt=, method=password +[BreakEscape] Found object: id=cabinet_password, name=Password Cabinet, locked=true, requires=secret123 +[BreakEscape] Password validation: required='secret123', attempt='', result=false +Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.1ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_RFID_lock:_should_trust_client_validation +-------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.5ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.473873"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.473707"], ["updated_at", "2025-11-22 00:41:06.473707"]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"door_rfid", "attempt"=>nil, "method"=>"rfid", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=object, id=door_rfid, attempt=, method=rfid +[BreakEscape] Found object: id=door_rfid, name=RFID Door, locked=true, requires=admin_badge + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"door_rfid\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.478975"], ["id", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.1ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlock_same_door_twice_should_be_idempotent +------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.482276"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.482108"], ["updated_at", "2025-11-22 00:41:06.482108"]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.486778"], ["id", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin +[BreakEscape] Door already unlocked in player state, granting access + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.7ms (4 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_correct_PIN_should_unlock +--------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.496374"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.496204"], ["updated_at", "2025-11-22 00:41:06.496204"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.500854"], ["id", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_player_has_not_encountered_NPC +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.504598"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.504410"], ["updated_at", "2025-11-22 00:41:06.504410"]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.3ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_pin\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["updated_at", "2025-11-22 00:41:06.505962"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin +[BreakEscape] Player has not encountered NPC: helper_npc +Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_multiple_unlock_attempts_should_update_state_correctly +------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.511970"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.511791"], ["updated_at", "2025-11-22 00:41:06.511791"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.518660"], ["id", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=door, id=office_password, attempt=opensesame, method=password + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\",\"office_password\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.523346"], ["id", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=object, id=safe_pin, attempt=1234, method=pin +[BreakEscape] Found object: id=safe_pin, name=PIN Safe, locked=true, requires=1234 +[BreakEscape] Password validation: required='1234', attempt='1234', result=true + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\",\"office_password\"],\"unlockedObjects\":[\"safe_pin\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.528164"], ["id", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.5ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.1ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_key_lock:_should_trust_client_validation +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.532345"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.532109"], ["updated_at", "2025-11-22 00:41:06.532109"]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"drawer_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=object, id=drawer_key, attempt=, method=key +[BreakEscape] Found object: id=drawer_key, name=Locked Drawer, locked=true, requires=drawer_key + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.3ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"drawer_key\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.537636"], ["id", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.1ms) begin transaction +----------------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_unlock_response_should_not_expose_'requires'_field_for_exploitable_locks +----------------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.541405"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.541234"], ["updated_at", "2025-11-22 00:41:06.541234"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=door, id=office_pin, attempt=9876, method=pin + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.545686"], ["id", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.1ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_key_lock:_should_trust_client_validation +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.549071"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.548892"], ["updated_at", "2025-11-22 00:41:06.548892"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=door, id=office_key, attempt=, method=key + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_key\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.553605"], ["id", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlocked_container:_should_grant_access_without_validation +---------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.557713"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.557533"], ["updated_at", "2025-11-22 00:41:06.557533"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=object, id=chest_unlocked, attempt=, method=unlocked +[BreakEscape] Found object: id=chest_unlocked, name=Open Chest, locked=false, requires= +[BreakEscape] Object is unlocked in scenario data, granting access + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"chest_unlocked\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.561837"], ["id", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_NPC_doesn't_have_permission_for_that_door +----------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.565370"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.565213"], ["updated_at", "2025-11-22 00:41:06.565213"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.2ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}],\"npcs\":[{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"unlockable\":[\"office_password\"]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.566668"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=door, id=office_pin, attempt=helper_npc, method=npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin +[BreakEscape] NPC helper_npc does not have permission to unlock office_pin +Completed 422 Unprocessable Content in 3ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlocked_door:_should_grant_access_without_validation +----------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.573543"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.573379"], ["updated_at", "2025-11-22 00:41:06.573379"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=door, id=office_unlocked, attempt=, method=unlocked +[BreakEscape] Door is unlocked in scenario data, granting access + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_unlocked\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.577909"], ["id", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.5ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.1ms) begin transaction +------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_bluetooth_lock:_should_trust_client_validation +------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.582019"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.581844"], ["updated_at", "2025-11-22 00:41:06.581844"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"terminal_bluetooth", "attempt"=>nil, "method"=>"bluetooth", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=object, id=terminal_bluetooth, attempt=, method=bluetooth +[BreakEscape] Found object: id=terminal_bluetooth, name=Bluetooth Terminal, locked=true, requires=admin_device + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"terminal_bluetooth\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.586758"], ["id", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlock_non-existent_object_should_fail +-------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.590170"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.590018"], ["updated_at", "2025-11-22 00:41:06.590018"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"non_existent_object", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=object, id=non_existent_object, attempt=1234, method=pin +[BreakEscape] Object not found: non_existent_object +Completed 422 Unprocessable Content in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.1ms) begin transaction +----------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_containers +----------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (0.1ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.3ms) INSERT INTO "break_escape_games" ("player_type", "player_id", "mission_id", "scenario_data", "player_state", "status", "started_at", "completed_at", "score", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["scenario_data", "{\"startRoom\":\"lobby\",\"rooms\":{\"lobby\":{\"type\":\"office_lobby\",\"locked\":false,\"connections\":{\"north\":\"office_pin\",\"south\":\"office_password\",\"east\":\"office_key\",\"west\":\"office_unlocked\"},\"objects\":[{\"id\":\"safe_pin\",\"name\":\"PIN Safe\",\"type\":\"safe\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"contents\":[{\"type\":\"document\",\"name\":\"Secret Document\"}]},{\"id\":\"cabinet_password\",\"name\":\"Password Cabinet\",\"type\":\"cabinet\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"secret123\",\"contents\":[{\"type\":\"key\",\"name\":\"Master Key\"}]},{\"id\":\"drawer_key\",\"name\":\"Locked Drawer\",\"type\":\"drawer\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"drawer_key\",\"contents\":[{\"type\":\"note\",\"name\":\"Important Note\"}]},{\"id\":\"box_lockpick\",\"name\":\"Lockpickable Box\",\"type\":\"box\",\"locked\":true,\"lockType\":\"lockpick\",\"difficulty\":3,\"contents\":[{\"type\":\"coin\",\"name\":\"Gold Coin\"}]},{\"id\":\"scanner_biometric\",\"name\":\"Biometric Scanner\",\"type\":\"scanner\",\"locked\":true,\"lockType\":\"biometric\",\"requires\":\"ceo_fingerprint\",\"contents\":[{\"type\":\"usb\",\"name\":\"Data USB\"}]},{\"id\":\"terminal_bluetooth\",\"name\":\"Bluetooth Terminal\",\"type\":\"terminal\",\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"admin_device\",\"contents\":[{\"type\":\"file\",\"name\":\"Access Codes\"}]},{\"id\":\"door_rfid\",\"name\":\"RFID Door\",\"type\":\"door\",\"locked\":true,\"lockType\":\"rfid\",\"requires\":\"admin_badge\",\"contents\":[{\"type\":\"keycard\",\"name\":\"Security Card\"}]},{\"id\":\"chest_unlocked\",\"name\":\"Open Chest\",\"type\":\"chest\",\"locked\":false,\"contents\":[{\"type\":\"tool\",\"name\":\"Wrench\"}]}]},\"office_pin\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9876\",\"connections\":{\"south\":\"lobby\"},\"objects\":[]},\"office_password\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"password\",\"requires\":\"opensesame\",\"connections\":{\"north\":\"lobby\"},\"objects\":[]},\"office_key\":{\"type\":\"office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office_key\",\"connections\":{\"west\":\"lobby\"},\"objects\":[]},\"office_unlocked\":{\"type\":\"office\",\"locked\":false,\"connections\":{\"east\":\"lobby\"},\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-22 00:41:06.595806"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-22 00:41:06.595656"], ["updated_at", "2025-11-22 00:41:06.595656"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-22 00:41:06 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::DemoUser Load (0.1ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] validate_unlock: type=object, id=chest_unlocked, attempt=, method=unlocked +[BreakEscape] Found object: id=chest_unlocked, name=Open Chest, locked=false, requires= +[BreakEscape] Object is unlocked in scenario data, granting access + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\"],\"unlockedObjects\":[\"chest_unlocked\"],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-22 00:41:06.599998"], ["id", 1]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 0.0ms) TRANSACTION (0.1ms) rollback transaction diff --git a/test/dummy/storage/test.sqlite3 b/test/dummy/storage/test.sqlite3 index bcdfde3..cfbecc3 100644 Binary files a/test/dummy/storage/test.sqlite3 and b/test/dummy/storage/test.sqlite3 differ