From 26fc297ad8a58f8ce229bc2dcf618d112b3245c0 Mon Sep 17 00:00:00 2001 From: "Z. Cliffe Schreuders" Date: Tue, 25 Nov 2025 16:28:18 +0000 Subject: [PATCH] Refactor tests and improve NPC handling - Updated NPC ink loading tests to ensure proper handling of missing story files. - Adjusted lazy loading tests for rooms to enhance clarity and maintainability. - Enhanced unlock system tests by adding inventory checks for keys. - Refined filtered scenario tests to ensure accurate preservation of game state. - Improved game model tests to validate unlock functionality with various inventory scenarios. --- .rubocop.yml | 4 + .../break_escape/games_controller.rb | 9 +- .../break_escape/missions_controller.rb | 4 +- .../break_escape/static_files_controller.rb | 25 +- app/models/break_escape/game.rb | 34 +- db/seeds.rb | 1 - lib/break_escape.rb | 2 +- lib/tasks/break_escape_tasks.rake | 1 - .../break_escape/games_controller_test.rb | 99 +- test/dummy/log/test.log | 18931 ++++++++++++++++ test/dummy/storage/test.sqlite3 | Bin 65536 -> 94208 bytes test/integration/npc_ink_loading_test.rb | 30 +- test/integration/room_lazy_load_test.rb | 4 +- test/integration/unlock_system_test.rb | 8 + .../break_escape/filtered_scenario_test.rb | 44 +- test/models/break_escape/game_test.rb | 22 +- 16 files changed, 19110 insertions(+), 108 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 833a574..3c2cc6a 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -7,6 +7,10 @@ inherit_gem: { rubocop-rails-omakase: rubocop.yml } Style/StringLiterals: Enabled: false +# Use `[a, [b, c]]` not `[ a, [ b, c ] ]` +Layout/SpaceInsideArrayLiteralBrackets: + Enabled: false + # # Use `[a, [b, c]]` not `[ a, [ b, c ] ]` # Layout/SpaceInsideArrayLiteralBrackets: # Enabled: false diff --git a/app/controllers/break_escape/games_controller.rb b/app/controllers/break_escape/games_controller.rb index 2ebdec8..4a53c04 100644 --- a/app/controllers/break_escape/games_controller.rb +++ b/app/controllers/break_escape/games_controller.rb @@ -92,6 +92,11 @@ module BreakEscape return render_error('Scenario data not available', :internal_server_error) end + # Check if room exists in scenario FIRST (before accessibility check) + unless @game.scenario_data['rooms']&.key?(room_id) + return render_error("Room not found: #{room_id}", :not_found) + end + # Check if room is accessible (starting room OR in unlockedRooms) is_start_room = @game.scenario_data['startRoom'] == room_id is_unlocked = @game.player_state['unlockedRooms']&.include?(room_id) @@ -628,14 +633,14 @@ module BreakEscape return npc if npc['id'] == npc_id end end - + # Log available NPCs for debugging if available_npcs.any? Rails.logger.debug "[BreakEscape] Available NPCs: #{available_npcs.join(', ')}" else Rails.logger.warn "[BreakEscape] No NPCs found in scenario data" end - + nil end diff --git a/app/controllers/break_escape/missions_controller.rb b/app/controllers/break_escape/missions_controller.rb index 7be3b0c..b4014c7 100644 --- a/app/controllers/break_escape/missions_controller.rb +++ b/app/controllers/break_escape/missions_controller.rb @@ -3,9 +3,9 @@ module BreakEscape def index @missions = if defined?(Pundit) policy_scope(Mission) - else + else Mission.published - end + end # Filter by collection if specified if params[:collection].present? diff --git a/app/controllers/break_escape/static_files_controller.rb b/app/controllers/break_escape/static_files_controller.rb index 4862b70..d384e2e 100644 --- a/app/controllers/break_escape/static_files_controller.rb +++ b/app/controllers/break_escape/static_files_controller.rb @@ -1,33 +1,33 @@ module BreakEscape class StaticFilesController < BreakEscape::ApplicationController skip_before_action :verify_authenticity_token - + def serve # Use the BreakEscape engine's root, not Rails.root engine_root = BreakEscape::Engine.root - + # Determine the actual file path based on the request URL request_path = request.path - + # Map different URL patterns to their file locations # Remember: request_path will be /break_escape/css/... when mounted at /break_escape file_path = case request_path - when %r{^/break_escape/css/} + when %r{^/break_escape/css/} engine_root.join('public', 'break_escape', 'css', params[:path]) - when %r{^/break_escape/js/} + when %r{^/break_escape/js/} engine_root.join('public', 'break_escape', 'js', params[:path]) - when %r{^/break_escape/assets/} + when %r{^/break_escape/assets/} engine_root.join('public', 'break_escape', 'assets', params[:path]) - when %r{^/break_escape/stylesheets/} + when %r{^/break_escape/stylesheets/} engine_root.join('public', 'break_escape', 'css', params[:path]) - when %r{^/break_escape/.*\.html$} + when %r{^/break_escape/.*\.html$} # HTML test files like /break_escape/test-assets.html engine_root.join('public', 'break_escape', "#{params[:filename]}.html") - else + else # Fallback for any other pattern engine_root.join('public', 'break_escape', params[:path]) - end - + end + # Security: prevent directory traversal base_path = engine_root.join('public', 'break_escape').to_s unless file_path.to_s.start_with?(base_path) @@ -40,7 +40,7 @@ module BreakEscape # Determine content type content_type = determine_content_type(file_path.to_s) - + send_file file_path, type: content_type, disposition: 'inline' rescue Errno::ENOENT render_not_found @@ -90,4 +90,3 @@ module BreakEscape end end end - diff --git a/app/models/break_escape/game.rb b/app/models/break_escape/game.rb index 4192ea5..3bc2633 100644 --- a/app/models/break_escape/game.rb +++ b/app/models/break_escape/game.rb @@ -61,22 +61,22 @@ module BreakEscape # Check if player has a specific key in inventory def has_key_in_inventory?(key_id) inventory = player_state['inventory'] || [] - + Rails.logger.info "[BreakEscape] Checking for key #{key_id} in inventory (#{inventory.length} items)" - + # Check for key with matching key_id found = inventory.any? do |item| - is_match = item['scenarioData']&.dig('key_id') == key_id || + is_match = item['scenarioData']&.dig('key_id') == key_id || item['scenarioData']&.dig('id') == key_id || item['key_id'] == key_id || item['id'] == key_id - + item_key_id = item['scenarioData']&.dig('key_id') || item['key_id'] item_name = item['scenarioData']&.dig('name') || item['name'] Rails.logger.debug "[BreakEscape] Inventory item: name=#{item_name}, key_id=#{item_key_id}, is_match=#{is_match}" is_match end - + Rails.logger.info "[BreakEscape] Key #{key_id} found in inventory: #{found}" found end @@ -84,9 +84,9 @@ module BreakEscape # Check if player has a lockpick in inventory def has_lockpick_in_inventory? inventory = player_state['inventory'] || [] - + Rails.logger.info "[BreakEscape] Checking for lockpick in inventory (#{inventory.length} items)" - + # Check for lockpick item in scenarioData or at top level found = inventory.any? do |item| is_lockpick = item['scenarioData']&.dig('type') == 'lockpick' || @@ -94,7 +94,7 @@ module BreakEscape Rails.logger.debug "[BreakEscape] Inventory item: type=#{item['type']}, scenarioData.type=#{item['scenarioData']&.dig('type')}, is_lockpick=#{is_lockpick}" is_lockpick end - + Rails.logger.info "[BreakEscape] Lockpick found in inventory: #{found}" found end @@ -149,7 +149,7 @@ module BreakEscape # Returns scenario data without room contents for lazy-loading # This significantly reduces initial payload by only sending metadata filtered = scenario_data.deep_dup - + # Remove all room contents - they'll be lazy-loaded via /room/:room_id endpoint if filtered['rooms'].present? filtered['rooms'].each do |room_id, room_data| @@ -160,12 +160,12 @@ module BreakEscape %w[type connections locked lockType requires difficulty door_sign keyPins].each do |field| kept_fields[field] = room_data[field] if room_data.key?(field) end - + # Replace room data with filtered version filtered['rooms'][room_id] = kept_fields end end - + filtered end @@ -199,7 +199,7 @@ module BreakEscape # If room is LOCKED, it requires validation if room['locked'] Rails.logger.info "[BreakEscape] Room is LOCKED, method must be valid: #{method}" - + # Handle method='unlocked' - REJECT for locked doors if method == 'unlocked' Rails.logger.warn "[BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED door: #{target_id}" @@ -240,15 +240,15 @@ module BreakEscape end Rails.logger.info "[BreakEscape] validate_unlock returning: #{result}" - return result + result else # Room is unlocked if method == 'unlocked' Rails.logger.info "[BreakEscape] Door is unlocked in scenario data, granting access" - return true + true else Rails.logger.warn "[BreakEscape] Client sent method='#{method}' for UNLOCKED door: #{target_id}, but room has no lock" - return true # Still allow access since room is unlocked + true # Still allow access since room is unlocked end end else @@ -373,11 +373,11 @@ module BreakEscape def initialize_player_state # Ensure player_state is always a hash self.player_state = {} unless self.player_state.is_a?(Hash) - + self.player_state['currentRoom'] ||= scenario_data['startRoom'] self.player_state['unlockedRooms'] ||= [scenario_data['startRoom']] self.player_state['unlockedObjects'] ||= [] - + # Ensure inventory is always an array, even if it was corrupted unless self.player_state['inventory'].is_a?(Array) self.player_state['inventory'] = [] diff --git a/db/seeds.rb b/db/seeds.rb index 80a3596..f59e01f 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -107,4 +107,3 @@ else puts ' Mode: Standalone (CyBOK data in break_escape_cyboks only)' end puts '=' * 50 - diff --git a/lib/break_escape.rb b/lib/break_escape.rb index f18e026..67c671d 100644 --- a/lib/break_escape.rb +++ b/lib/break_escape.rb @@ -26,4 +26,4 @@ module BreakEscape end # Initialize with defaults -BreakEscape.configure {} +BreakEscape.configure { } diff --git a/lib/tasks/break_escape_tasks.rake b/lib/tasks/break_escape_tasks.rake index 863bb90..b2acbc5 100644 --- a/lib/tasks/break_escape_tasks.rake +++ b/lib/tasks/break_escape_tasks.rake @@ -4,4 +4,3 @@ namespace :break_escape do load File.join(BreakEscape::Engine.root, 'db', 'seeds.rb') end end - diff --git a/test/controllers/break_escape/games_controller_test.rb b/test/controllers/break_escape/games_controller_test.rb index 44cca75..d2fc2e4 100644 --- a/test/controllers/break_escape/games_controller_test.rb +++ b/test/controllers/break_escape/games_controller_test.rb @@ -10,7 +10,33 @@ module BreakEscape @game = Game.create!( mission: @mission, player: @player, - scenario_data: { "startRoom" => "reception", "rooms" => {} }, + scenario_data: { + "startRoom" => "reception", + "startItemsInInventory" => [ + { + "type" => "lockpick", + "name" => "Lockpick", + "id" => "lockpick_1", + "takeable" => true + } + ], + "rooms" => { + "reception" => { + "type" => "room_reception", + "connections" => { "north" => "office" }, + "locked" => false, + "objects" => [] + }, + "office" => { + "type" => "office", + "connections" => { "south" => "reception" }, + "locked" => true, + "lockType" => "pin", + "requires" => "1234", + "objects" => [] + } + } + }, player_state: { "currentRoom" => "reception", "unlockedRooms" => ["reception"], @@ -59,23 +85,9 @@ module BreakEscape assert json['rooms'] end - test "bootstrap endpoint should return game state" do - get bootstrap_game_url(@game) - assert_response :success - assert_equal 'application/json', @response.media_type - - json = JSON.parse(@response.body) - assert_equal @game.id, json['gameId'] - assert_equal 'reception', json['startRoom'] - assert json['playerState'] - assert_equal 'reception', json['playerState']['currentRoom'] - assert_includes json['playerState']['unlockedRooms'], 'reception' - assert_equal 100, json['playerState']['health'] - end - - test "sync_state should update player state" do + test "sync_state should update player state for current room" do put sync_state_game_url(@game), params: { - currentRoom: 'office' + currentRoom: 'reception' } assert_response :success @@ -83,7 +95,7 @@ module BreakEscape assert json['success'] @game.reload - assert_equal 'office', @game.player_state['currentRoom'] + assert_equal 'reception', @game.player_state['currentRoom'] end test "unlock endpoint should reject invalid attempts" do @@ -91,7 +103,7 @@ module BreakEscape targetType: 'room', targetId: 'office', attempt: 'wrong_code', - method: 'keypad' + method: 'pin' } assert_response :unprocessable_entity @@ -100,10 +112,55 @@ module BreakEscape assert_equal 'Invalid attempt', json['message'] end + test "game setup has correct scenario data" do + # Verify the test setup is correct before running unlock tests + assert @game.scenario_data['rooms']['office'].present? + office = @game.scenario_data['rooms']['office'] + assert_equal true, office['locked'] + assert_equal 'pin', office['lockType'] + assert_equal '1234', office['requires'] + end + + test "unlock endpoint should accept correct pin code" do + # Debug: Check scenario before making request + assert @game.scenario_data['rooms']['office']['requires'] == '1234', + "Office room should require PIN 1234, but requires: #{@game.scenario_data['rooms']['office']['requires']}" + + post unlock_game_url(@game), params: { + targetType: 'door', + targetId: 'office', + attempt: '1234', + method: 'pin' + } + + assert_response :success, + "Expected 200, got #{@response.status}. Response: #{response.body}" + json = JSON.parse(@response.body) + assert json['success'], "Response success should be true: #{json}" + assert_equal 'door', json['type'] + assert json['roomData'] + + @game.reload + assert_includes @game.player_state['unlockedRooms'], 'office' + end + test "inventory endpoint should add items" do + # Create a test scenario that doesn't include the lockpick in starting items + @game.scenario_data['startItemsInInventory'] = [] + @game.scenario_data['rooms']['reception']['objects'] = [ + { + "id" => "note_1", + "type" => "note", + "name" => "Test Note", + "takeable" => true + } + ] + @game.player_state['inventory'] = [] + @game.save! + post inventory_game_url(@game), params: { action_type: 'add', - item: { type: 'key', name: 'Test Key', id: 'test_key' } + item: { type: 'note', name: 'Test Note', id: 'note_1' } } assert_response :success @@ -130,7 +187,7 @@ module BreakEscape test "ink endpoint should return 404 for NPC without story file" do # Game doesn't have NPCs with story files by default - get ink_game_url(@game), params: { npc: 'test-npc' } + get ink_game_url(@game), params: { npc: 'missing-npc' } assert_response :not_found end end diff --git a/test/dummy/log/test.log b/test/dummy/log/test.log index 1908eda..78794ee 100644 --- a/test/dummy/log/test.log +++ b/test/dummy/log/test.log @@ -29624,3 +29624,18934 @@ BreakEscape::GameTest: test_should_track_inventory BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"key\",\"name\":\"Test Key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-24 11:19:17.614926"], ["id", 1]] TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 TRANSACTION (0.0ms) rollback transaction + ActiveRecord::InternalMetadata Load (0.1ms) 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.1ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC + ActiveRecord::InternalMetadata Load (0.0ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "environment"]] + ActiveRecord::SchemaMigration Load (0.0ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC + ActiveRecord::InternalMetadata Load (0.0ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "environment"]] + ActiveRecord::SchemaMigration Load (0.0ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC + ActiveRecord::InternalMetadata Load (0.0ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "environment"]] +  (0.1ms) DROP TABLE IF EXISTS "break_escape_cyboks" +  (0.6ms) CREATE TABLE "break_escape_cyboks" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "ka" varchar, "topic" varchar, "keywords" varchar, "cybokable_type" varchar, "cybokable_id" integer, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL) +  (0.0ms) CREATE INDEX "index_break_escape_cyboks_on_cybokable_id" ON "break_escape_cyboks" ("cybokable_id") +  (0.0ms) CREATE INDEX "index_break_escape_cyboks_on_cybokable_type_and_cybokable_id" ON "break_escape_cyboks" ("cybokable_type", "cybokable_id") +  (0.0ms) CREATE INDEX "index_break_escape_cyboks_on_ka" ON "break_escape_cyboks" ("ka") +  (0.0ms) DROP TABLE IF EXISTS "break_escape_demo_users" +  (0.0ms) CREATE TABLE "break_escape_demo_users" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "handle" varchar NOT NULL, "role" varchar DEFAULT 'user' NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL) +  (0.0ms) CREATE UNIQUE INDEX "index_break_escape_demo_users_on_handle" ON "break_escape_demo_users" ("handle") +  (0.0ms) DROP TABLE IF EXISTS "break_escape_games" +  (0.1ms) CREATE TABLE "break_escape_games" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "player_type" varchar NOT NULL, "player_id" integer NOT NULL, "mission_id" integer NOT NULL, "scenario_data" json NOT NULL, "player_state" json DEFAULT '"{\"currentRoom\":null,\"unlockedRooms\":[],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"' NOT NULL, "status" varchar DEFAULT 'in_progress' NOT NULL, "started_at" datetime(6), "completed_at" datetime(6), "score" integer DEFAULT 0 NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL) +  (0.0ms) CREATE INDEX "index_break_escape_games_on_mission_id" ON "break_escape_games" ("mission_id") +  (0.0ms) CREATE UNIQUE INDEX "index_games_on_player_and_mission" ON "break_escape_games" ("player_type", "player_id", "mission_id") +  (0.0ms) CREATE INDEX "index_break_escape_games_on_player" ON "break_escape_games" ("player_type", "player_id") +  (0.0ms) CREATE INDEX "index_break_escape_games_on_status" ON "break_escape_games" ("status") +  (0.0ms) DROP TABLE IF EXISTS "break_escape_missions" +  (0.0ms) CREATE TABLE "break_escape_missions" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar NOT NULL, "display_name" varchar NOT NULL, "description" text, "published" boolean DEFAULT 0 NOT NULL, "difficulty_level" integer DEFAULT 1 NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "secgen_scenario" varchar, "collection" varchar DEFAULT 'default') +  (0.0ms) CREATE INDEX "index_break_escape_missions_on_collection" ON "break_escape_missions" ("collection") +  (0.0ms) CREATE UNIQUE INDEX "index_break_escape_missions_on_name" ON "break_escape_missions" ("name") +  (0.0ms) CREATE INDEX "index_break_escape_missions_on_published" ON "break_escape_missions" ("published") +  (0.0ms) PRAGMA foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys = ON +  (0.0ms) PRAGMA foreign_keys = OFF + TRANSACTION (0.0ms) begin transaction +  (0.1ms) CREATE TEMPORARY TABLE "abreak_escape_games" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "player_type" varchar NOT NULL, "player_id" integer NOT NULL, "mission_id" integer NOT NULL, "scenario_data" json NOT NULL, "player_state" json DEFAULT '"{\"currentRoom\":null,\"unlockedRooms\":[],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"' NOT NULL, "status" varchar DEFAULT 'in_progress' NOT NULL, "started_at" datetime(6), "completed_at" datetime(6), "score" integer DEFAULT 0 NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL) +  (0.0ms) CREATE INDEX "tindex_abreak_escape_games_on_status" ON "abreak_escape_games" ("status") +  (0.0ms) CREATE INDEX "tindex_abreak_escape_games_on_player" ON "abreak_escape_games" ("player_type", "player_id") +  (0.0ms) CREATE UNIQUE INDEX "tindex_games_on_player_and_mission" ON "abreak_escape_games" ("player_type", "player_id", "mission_id") +  (0.0ms) CREATE INDEX "tindex_abreak_escape_games_on_mission_id" ON "abreak_escape_games" ("mission_id") +  (0.0ms) INSERT INTO "abreak_escape_games" ("id","player_type","player_id","mission_id","scenario_data","player_state","status","started_at","completed_at","score","created_at","updated_at") + SELECT "id","player_type","player_id","mission_id","scenario_data","player_state","status","started_at","completed_at","score","created_at","updated_at" FROM "break_escape_games" +  (0.1ms) DROP TABLE "break_escape_games" +  (0.0ms) CREATE TABLE "break_escape_games" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "player_type" varchar NOT NULL, "player_id" integer NOT NULL, "mission_id" integer NOT NULL, "scenario_data" json NOT NULL, "player_state" json DEFAULT '"{\"currentRoom\":null,\"unlockedRooms\":[],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"' NOT NULL, "status" varchar DEFAULT 'in_progress' NOT NULL, "started_at" datetime(6), "completed_at" datetime(6), "score" integer DEFAULT 0 NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, CONSTRAINT "fk_rails_ce758a8dd4" +FOREIGN KEY ("mission_id") + REFERENCES "break_escape_missions" ("id") +) +  (0.0ms) CREATE INDEX "index_break_escape_games_on_mission_id" ON "break_escape_games" ("mission_id") +  (0.0ms) CREATE UNIQUE INDEX "index_games_on_player_and_mission" ON "break_escape_games" ("player_type", "player_id", "mission_id") +  (0.0ms) CREATE INDEX "index_break_escape_games_on_player" ON "break_escape_games" ("player_type", "player_id") +  (0.0ms) CREATE INDEX "index_break_escape_games_on_status" ON "break_escape_games" ("status") +  (0.0ms) INSERT INTO "break_escape_games" ("id","player_type","player_id","mission_id","scenario_data","player_state","status","started_at","completed_at","score","created_at","updated_at") + SELECT "id","player_type","player_id","mission_id","scenario_data","player_state","status","started_at","completed_at","score","created_at","updated_at" FROM "abreak_escape_games" +  (0.1ms) DROP TABLE "abreak_escape_games" + TRANSACTION (0.0ms) commit transaction +  (0.0ms) PRAGMA defer_foreign_keys = 0 +  (0.0ms) PRAGMA foreign_keys = 1 +  (0.1ms) CREATE TABLE "schema_migrations" ("version" varchar NOT NULL PRIMARY KEY) + ActiveRecord::SchemaMigration Load (0.0ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC +  (0.0ms) INSERT INTO "schema_migrations" (version) VALUES (20251125000002) +  (0.0ms) INSERT INTO "schema_migrations" (version) VALUES +(20251125000001), +(20251120160000), +(20251120155358), +(20251120155357); +  (0.0ms) CREATE TABLE "ar_internal_metadata" ("key" varchar NOT NULL PRIMARY KEY, "value" varchar, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL) + ActiveRecord::InternalMetadata Load (0.0ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "environment"]] + ActiveRecord::InternalMetadata Create (0.0ms) INSERT INTO "ar_internal_metadata" ("key", "value", "created_at", "updated_at") VALUES ('environment', 'test', '2025-11-25 16:20:28.390523', '2025-11-25 16:20:28.390524') RETURNING "key" + ActiveRecord::InternalMetadata Load (0.0ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "environment"]] + ActiveRecord::InternalMetadata Load (0.0ms) SELECT * FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? ORDER BY "ar_internal_metadata"."key" ASC LIMIT 1 [[nil, "schema_sha1"]] + ActiveRecord::InternalMetadata Create (0.0ms) INSERT INTO "ar_internal_metadata" ("key", "value", "created_at", "updated_at") VALUES ('schema_sha1', 'c41fb8b3ebbf02b760a2e198c701a78020d1c2a5', '2025-11-25 16:20:28.390824', '2025-11-25 16:20:28.390825') RETURNING "key" + ActiveRecord::SchemaMigration Load (0.0ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC + TRANSACTION (0.0ms) begin transaction +  (0.1ms) PRAGMA foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys = ON +  (0.0ms) PRAGMA foreign_keys = OFF + Fixtures Load (0.1ms) 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-25 16:20:28', '2025-11-25 16:20:28'); +INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-25 16:20:28', '2025-11-25 16:20:28'); +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-25 16:20:28', '2025-11-25 16:20:28'); +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-25 16:20:28', '2025-11-25 16:20:28') +  (0.0ms) PRAGMA defer_foreign_keys = 0 +  (0.0ms) PRAGMA foreign_keys = 1 + TRANSACTION (1.5ms) commit transaction +  (0.0ms) PRAGMA foreign_key_check + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------- +BreakEscape::GameTest: test_key_takes_precedence_over_lockpick_attempt +---------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.461874"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.461794"], ["updated_at", "2025-11-25 16:20:28.461794"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=key +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office1_key in inventory (2 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=true +[BreakEscape] Key office1_key found in inventory: true +[BreakEscape] Key validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------ +BreakEscape::GameTest: test_lockpick_should_bypass_key_requirement +------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.463353"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.463324"], ["updated_at", "2025-11-25 16:20:28.463324"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=secure_vault, attempt=, method=lockpick +[BreakEscape] Room data: locked=true, lockType=key, requires=vault_master_key +[BreakEscape] Room is LOCKED, method must be valid: lockpick +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=lockpick, scenarioData.type=, is_lockpick=true +[BreakEscape] Lockpick found in inventory: true +[BreakEscape] Lockpick validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::GameTest: test_should_reject_locked_door_without_any_unlock_method +------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.2ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.464467"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.464436"], ["updated_at", "2025-11-25 16:20:28.464436"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method= +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: +[BreakEscape] SECURITY VIOLATION: No valid unlock method for LOCKED door: office1, method= +[BreakEscape] validate_unlock returning: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------- +BreakEscape::GameTest: test_should_unlock_room +---------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.465745"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.465713"], ["updated_at", "2025-11-25 16:20:28.465713"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\",\"office\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:20:28.466207"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GameTest: test_has_lockpick_in_inventory_should_find_lockpicks +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.467146"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.467119"], ["updated_at", "2025-11-25 16:20:28.467119"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=lockpick, scenarioData.type=, is_lockpick=true +[BreakEscape] Lockpick found in inventory: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------- +BreakEscape::GameTest: test_should_reject_lockpick_unlock_without_lockpick_in_inventory +--------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.468130"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.468102"], ["updated_at", "2025-11-25 16:20:28.468102"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=lockpick +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: lockpick +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=key, scenarioData.type=, is_lockpick=false +[BreakEscape] Lockpick found in inventory: false +[BreakEscape] Lockpick validation result: false +[BreakEscape] validate_unlock returning: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------- +BreakEscape::GameTest: test_should_reject_unlock_without_required_key +--------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.469102"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.469076"], ["updated_at", "2025-11-25 16:20:28.469076"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=key +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office1_key in inventory (1 items) +[BreakEscape] Inventory item: name=Wrong Key, key_id=wrong_key, is_match=false +[BreakEscape] Key office1_key found in inventory: false +[BreakEscape] Key validation result: false +[BreakEscape] validate_unlock returning: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------- +BreakEscape::GameTest: test_should_belong_to_player_and_mission +--------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.470073"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.470047"], ["updated_at", "2025-11-25 16:20:28.470047"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------- +BreakEscape::GameTest: test_should_validate_unlock_with_lockpick +---------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.471045"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.471013"], ["updated_at", "2025-11-25 16:20:28.471013"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=lockpick +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: lockpick +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=lockpick, scenarioData.type=, is_lockpick=true +[BreakEscape] Lockpick found in inventory: true +[BreakEscape] Lockpick validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GameTest: test_has_key_in_inventory_should_find_keys_by_key_id +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.472081"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.472053"], ["updated_at", "2025-11-25 16:20:28.472053"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Checking for key office1_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=true +[BreakEscape] Key office1_key found in inventory: true +[BreakEscape] Checking for key wrong_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=false +[BreakEscape] Key wrong_key found in inventory: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------ +BreakEscape::GameTest: test_should_update_health +------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.473088"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.473037"], ["updated_at", "2025-11-25 16:20:28.473037"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":50}"], ["updated_at", "2025-11-25 16:20:28.473564"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::GameTest: test_should_allow_access_to_unlocked_doors_regardless_of_method +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.474428"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.474403"], ["updated_at", "2025-11-25 16:20:28.474403"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=reception, attempt=, method=unlocked +[BreakEscape] Door already unlocked in player state, granting access + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------- +BreakEscape::GameTest: test_should_clamp_health_between_0_and_100 +----------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.475369"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.475344"], ["updated_at", "2025-11-25 16:20:28.475344"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":0}"], ["updated_at", "2025-11-25 16:20:28.475899"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------- +BreakEscape::GameTest: test_should_track_inventory +-------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.476735"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.476705"], ["updated_at", "2025-11-25 16:20:28.476705"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"key\",\"name\":\"Test Key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:20:28.477160"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------- +BreakEscape::GameTest: test_has_lockpick_in_inventory_should_not_find_non-lockpick_items +---------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.478012"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.477986"], ["updated_at", "2025-11-25 16:20:28.477986"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=key, scenarioData.type=, is_lockpick=false +[BreakEscape] Lockpick found in inventory: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------- +BreakEscape::GameTest: test_should_validate_unlock_with_correct_key +------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.479017"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.478986"], ["updated_at", "2025-11-25 16:20:28.478986"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=key +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office1_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=true +[BreakEscape] Key office1_key found in inventory: true +[BreakEscape] Key validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_phone-chat-ui_should_import_ASSETS_PATH_from_config +---------------------------------------------------------------------------------------- + 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.0ms) 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.2ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.495939"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.495888"], ["updated_at", "2025-11-25 16:20:28.495888"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/phone-chat/phone-chat-ui.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/phone-chat/phone-chat-ui.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/phone-chat/phone-chat-ui.js (1.1ms) +Completed 200 OK in 2ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_npc-lazy-loader_should_construct_correct_API_endpoint_URL +---------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.508254"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.508212"], ["updated_at", "2025-11-25 16:20:28.508212"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/systems/npc-lazy-loader.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/npc-lazy-loader.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/npc-lazy-loader.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_npc-manager_should_load_stories_via_API_endpoint +------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.510094"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.510060"], ["updated_at", "2025-11-25 16:20:28.510060"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/systems/npc-manager.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/npc-manager.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/npc-manager.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::NPCInkLoadingTest: test_person-chat-portraits_should_import_ASSETS_PATH_from_config +------------------------------------------------------------------------------------------------ + 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.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.511991"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.511891"], ["updated_at", "2025-11-25 16:20:28.511891"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/person-chat/person-chat-portraits.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/person-chat/person-chat-portraits.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/person-chat/person-chat-portraits.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_404_for_non-existent_NPC +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.2ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.513943"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.513910"], ["updated_at", "2025-11-25 16:20:28.513910"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=non-existent-npc" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"non-existent-npc", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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] Loading ink for NPC: non-existent-npc +[BreakEscape] Available NPCs: security_guard (test_room), test-npc (test_room) +Completed 404 Not Found in 2ms (Views: 0.1ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_bad_request_if_npc_parameter_missing +--------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.519794"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.519755"], ["updated_at", "2025-11-25 16:20:28.519755"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 400 Bad Request in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.1ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_ink_endpoint_should_work_with_underscored_NPC_IDs +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.521940"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.521907"], ["updated_at", "2025-11-25 16:20:28.521907"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=npc-with-underscores" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"npc-with-underscores", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: npc-with-underscores +[BreakEscape] Available NPCs: security_guard (test_room), test-npc (test_room) +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_ink_endpoint_should_return_application/json_content_type +--------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.523916"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.523885"], ["updated_at", "2025-11-25 16:20:28.523885"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=security_guard" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"security_guard", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: security_guard +[BreakEscape] Found NPC: security_guard with storyPath: scenarios/ink/security-guard.json +[BreakEscape] Serving ink from: /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/scenarios/ink/security-guard.json +Completed 200 OK in 1ms (Views: 0.4ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_404_for_NPC_without_story_file +--------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.526349"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.526319"], ["updated_at", "2025-11-25 16:20:28.526319"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=npc-with-no-file" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"npc-with-no-file", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: npc-with-no-file +[BreakEscape] Available NPCs: security_guard (test_room), test-npc (test_room) +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_person-chat-minigame_should_use_Rails_API_endpoint_for_story_loading +--------------------------------------------------------------------------------------------------------- + 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.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.528563"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.528460"], ["updated_at", "2025-11-25 16:20:28.528460"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/person-chat/person-chat-minigame.js?v=10" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"v"=>"10", "path"=>"minigames/person-chat/person-chat-minigame.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/person-chat/person-chat-minigame.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_phone-chat-minigame_should_use_Rails_API_endpoint_for_story_loading +-------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.530343"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.530311"], ["updated_at", "2025-11-25 16:20:28.530311"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/phone-chat/phone-chat-minigame.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/phone-chat/phone-chat-minigame.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/phone-chat/phone-chat-minigame.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_404_for_non-existent_game +---------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.532042"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.532009"], ["updated_at", "2025-11-25 16:20:28.532009"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/999999/ink?npc=test-npc" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"test-npc", "id"=>"999999"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 999999], ["LIMIT", 1]] +Completed 404 Not Found in 1ms (ActiveRecord: 0.0ms (1 query, 0 cached) | GC: 0.4ms) + +ActiveRecord::RecordNotFound (Couldn't find BreakEscape::Game with 'id'="999999"): + +activerecord (7.2.3) lib/active_record/core.rb:268:in `find' +/home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/controllers/break_escape/games_controller.rb:323:in `set_game' +activesupport (7.2.3) lib/active_support/callbacks.rb:362:in `block in make_lambda' +activesupport (7.2.3) lib/active_support/callbacks.rb:179:in `block in call' +actionpack (7.2.3) lib/abstract_controller/callbacks.rb:34:in `block (2 levels) in ' +activesupport (7.2.3) lib/active_support/callbacks.rb:180:in `call' +activesupport (7.2.3) lib/active_support/callbacks.rb:560:in `block in invoke_before' +activesupport (7.2.3) lib/active_support/callbacks.rb:560:in `each' +activesupport (7.2.3) lib/active_support/callbacks.rb:560:in `invoke_before' +activesupport (7.2.3) lib/active_support/callbacks.rb:119:in `block in run_callbacks' +actiontext (7.2.3) lib/action_text/rendering.rb:25:in `with_renderer' +actiontext (7.2.3) lib/action_text/engine.rb:71:in `block (4 levels) in ' +activesupport (7.2.3) lib/active_support/callbacks.rb:130:in `instance_exec' +activesupport (7.2.3) lib/active_support/callbacks.rb:130:in `block in run_callbacks' +activesupport (7.2.3) lib/active_support/callbacks.rb:141:in `run_callbacks' +actionpack (7.2.3) lib/abstract_controller/callbacks.rb:260:in `process_action' +actionpack (7.2.3) lib/action_controller/metal/rescue.rb:27:in `process_action' +actionpack (7.2.3) lib/action_controller/metal/instrumentation.rb:77:in `block in process_action' +activesupport (7.2.3) lib/active_support/notifications.rb:210:in `block in instrument' +activesupport (7.2.3) lib/active_support/notifications/instrumenter.rb:58:in `instrument' +activesupport (7.2.3) lib/active_support/notifications.rb:210:in `instrument' +actionpack (7.2.3) lib/action_controller/metal/instrumentation.rb:76:in `process_action' +actionpack (7.2.3) lib/action_controller/metal/params_wrapper.rb:259:in `process_action' +activerecord (7.2.3) lib/active_record/railties/controller_runtime.rb:39:in `process_action' +actionpack (7.2.3) lib/abstract_controller/base.rb:152:in `process' +actionview (7.2.3) lib/action_view/rendering.rb:40:in `process' +actionpack (7.2.3) lib/action_controller/metal.rb:252:in `dispatch' +actionpack (7.2.3) lib/action_controller/metal.rb:335:in `dispatch' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:67:in `dispatch' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:50:in `serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:53:in `block in serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:133:in `block in find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `each' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:34:in `serve' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:896:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/static.rb:27:in `call' +railties (7.2.3) lib/rails/engine.rb:535:in `call' +railties (7.2.3) lib/rails/railtie.rb:226:in `public_send' +railties (7.2.3) lib/rails/railtie.rb:226:in `method_missing' +actionpack (7.2.3) lib/action_dispatch/routing/mapper.rb:33:in `block in ' +actionpack (7.2.3) lib/action_dispatch/routing/mapper.rb:62:in `serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:53:in `block in serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:133:in `block in find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `each' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:34:in `serve' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:896:in `call' +rack (3.2.4) lib/rack/tempfile_reaper.rb:20:in `call' +rack (3.2.4) lib/rack/etag.rb:29:in `call' +rack (3.2.4) lib/rack/conditional_get.rb:31:in `call' +rack (3.2.4) lib/rack/head.rb:15:in `call' +actionpack (7.2.3) lib/action_dispatch/http/permissions_policy.rb:38:in `call' +actionpack (7.2.3) lib/action_dispatch/http/content_security_policy.rb:38:in `call' +rack-session (2.1.1) lib/rack/session/abstract/id.rb:274:in `context' +rack-session (2.1.1) lib/rack/session/abstract/id.rb:268:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/cookies.rb:704:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/callbacks.rb:31:in `block in call' +activesupport (7.2.3) lib/active_support/callbacks.rb:101:in `run_callbacks' +actionpack (7.2.3) lib/action_dispatch/middleware/callbacks.rb:30:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/actionable_exceptions.rb:18:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/debug_exceptions.rb:31:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/show_exceptions.rb:32:in `call' +railties (7.2.3) lib/rails/rack/logger.rb:41:in `call_app' +railties (7.2.3) lib/rails/rack/logger.rb:29:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/remote_ip.rb:96:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/request_id.rb:33:in `call' +rack (3.2.4) lib/rack/method_override.rb:28:in `call' +rack (3.2.4) lib/rack/runtime.rb:24:in `call' +activesupport (7.2.3) lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/executor.rb:16:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/static.rb:27:in `call' +rack (3.2.4) lib/rack/sendfile.rb:131:in `call' +railties (7.2.3) lib/rails/engine.rb:535:in `call' +rack-test (2.2.0) lib/rack/test.rb:360:in `process_request' +rack-test (2.2.0) lib/rack/test.rb:153:in `request' +actionpack (7.2.3) lib/action_dispatch/testing/integration.rb:287:in `process' +actionpack (7.2.3) lib/action_dispatch/testing/integration.rb:19:in `get' +actionpack (7.2.3) lib/action_dispatch/testing/integration.rb:378:in `get' +/home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/test/integration/npc_ink_loading_test.rb:155:in `block in ' +minitest (5.26.2) lib/minitest/test.rb:95:in `block (2 levels) in run' +minitest (5.26.2) lib/minitest/test.rb:191:in `capture_exceptions' +minitest (5.26.2) lib/minitest/test.rb:90:in `block in run' +minitest (5.26.2) lib/minitest.rb:383:in `time_it' +minitest (5.26.2) lib/minitest/test.rb:89:in `run' +activesupport (7.2.3) lib/active_support/executor/test_helper.rb:5:in `block in run' +activesupport (7.2.3) lib/active_support/execution_wrapper.rb:104:in `perform' +activesupport (7.2.3) lib/active_support/executor/test_helper.rb:5:in `run' +minitest (5.26.2) lib/minitest.rb:1224:in `run_one_method' +minitest (5.26.2) lib/minitest.rb:463:in `run_one_method' +minitest (5.26.2) lib/minitest.rb:450:in `block (2 levels) in run' +minitest (5.26.2) lib/minitest.rb:446:in `each' +minitest (5.26.2) lib/minitest.rb:446:in `block in run' +minitest (5.26.2) lib/minitest.rb:488:in `on_signal' +minitest (5.26.2) lib/minitest.rb:475:in `with_info_handler' +minitest (5.26.2) lib/minitest.rb:445:in `run' +railties (7.2.3) lib/rails/test_unit/line_filtering.rb:10:in `run' +minitest (5.26.2) lib/minitest.rb:347:in `block in __run' +minitest (5.26.2) lib/minitest.rb:347:in `map' +minitest (5.26.2) lib/minitest.rb:347:in `__run' +minitest (5.26.2) lib/minitest.rb:302:in `run' +minitest (5.26.2) lib/minitest.rb:86:in `block in autorun' + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------ +BreakEscape::NPCInkLoadingTest: test_npc-barks_should_import_ASSETS_PATH_from_config +------------------------------------------------------------------------------------ + 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.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.688899"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.688849"], ["updated_at", "2025-11-25 16:20:28.688849"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/systems/npc-barks.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/npc-barks.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/npc-barks.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_incorrect_PIN_should_fail +--------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.691135"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.691066"], ["updated_at", "2025-11-25 16:20:28.691066"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: false +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_password_lock:_correct_password_should_unlock +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.696056"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.695990"], ["updated_at", "2025-11-25 16:20:28.695990"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:20:28.698367"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 2ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlock_with_invalid_method_should_fail +-------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.699976"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.699911"], ["updated_at", "2025-11-25 16:20:28.699911"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: invalid_method +[BreakEscape] SECURITY VIOLATION: No valid unlock method for LOCKED door: office_pin, method=invalid_method +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_doors +------------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.702274"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.702212"], ["updated_at", "2025-11-25 16:20:28.702212"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=false, lockType=, requires= +[BreakEscape] Door is unlocked in scenario data, granting access + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) 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-25 16:20:28.703928"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 3ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 1.2ms) + TRANSACTION (0.0ms) 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.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.706457"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.706391"], ["updated_at", "2025-11-25 16:20:28.706391"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:20:28.707240"], ["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-25 16:20:28 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:20:28.709061"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_unlock_non-existent_door_should_fail +------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.710548"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.710480"], ["updated_at", "2025-11-25 16:20:28.710480"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_biometric_lock:_should_trust_client_validation +------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.712810"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.712746"], ["updated_at", "2025-11-25 16:20:28.712746"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"scanner_biometric", "attempt"=>nil, "method"=>"biometric", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:20:28.714571"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_correct_PIN_should_unlock +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.716049"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.715984"], ["updated_at", "2025-11-25 16:20:28.715984"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:20:28.717911"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_key_lock:_should_trust_client_validation +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.719360"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.719292"], ["updated_at", "2025-11-25 16:20:28.719292"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"drawer_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:20:28.720958"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlock_same_door_twice_should_be_idempotent +------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.722189"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.722129"], ["updated_at", "2025-11-25 16:20:28.722129"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:20:28.723882"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_already-unlocked_door_accepts_method='unlocked' +----------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.726649"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.726588"], ["updated_at", "2025-11-25 16:20:28.726588"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:20:28.727253"], ["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-25 16:20:28 +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.0ms) 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.0ms) 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] Room data: locked=true, lockType=password, requires=TopSecret123 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=ceo +[BreakEscape] NPC unlock validated: helper_npc can unlock ceo + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:20:28.728919"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"ceo", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_player_has_not_encountered_NPC +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.731819"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.731653"], ["updated_at", "2025-11-25 16:20:28.731653"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:20:28.732398"], ["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-25 16:20:28 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin +[BreakEscape] Player has not encountered NPC: helper_npc +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_password_lock:_case_sensitivity +----------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.734865"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.734800"], ["updated_at", "2025-11-25 16:20:28.734800"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"OpenSesame", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: false +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) 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.0ms) 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.1ms) 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-25 16:20:28.737200"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.737137"], ["updated_at", "2025-11-25 16:20:28.737137"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:20:28.737733"], ["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-25 16:20:28 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_key_lock:_should_trust_client_validation +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.740077"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.740010"], ["updated_at", "2025-11-25 16:20:28.740010"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_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\":[],\"inventory\":[{\"id\":\"office_key\",\"type\":\"key\",\"name\":\"Office Key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:20:28.740592"], ["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-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=key, requires=office_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=, is_match=true +[BreakEscape] Key office_key found in inventory: true +[BreakEscape] Key validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_key\"],\"unlockedObjects\":[],\"inventory\":[{\"id\":\"office_key\",\"type\":\"key\",\"name\":\"Office Key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:20:28.742098"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_correct_PIN_should_unlock +--------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.743440"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.743378"], ["updated_at", "2025-11-25 16:20:28.743378"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:20:28.744999"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_password_lock:_incorrect_password_should_fail +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.746375"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.746312"], ["updated_at", "2025-11-25 16:20:28.746312"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"wrongpassword", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: false +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_lockpick:_should_trust_client_validation +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.748553"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.748491"], ["updated_at", "2025-11-25 16:20:28.748491"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"box_lockpick", "attempt"=>nil, "method"=>"lockpick", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:20:28.750171"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_incorrect_PIN_should_fail +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.751361"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.751297"], ["updated_at", "2025-11-25 16:20:28.751297"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_unlock_response_should_not_expose_'requires'_field_for_exploitable_locks +----------------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.753450"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.753386"], ["updated_at", "2025-11-25 16:20:28.753386"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:20:28.755039"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_NPC_unlock_adds_door_to_unlockedRooms +------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.756238"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.756176"], ["updated_at", "2025-11-25 16:20:28.756176"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:20:28.756782"], ["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-25 16:20:28 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin +[BreakEscape] NPC unlock validated: helper_npc can unlock office_pin + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:20:28.758369"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_for_non-existent_NPC +----------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.759759"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.759696"], ["updated_at", "2025-11-25 16:20:28.759696"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_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\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:20:28.760282"], ["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-25 16:20:28 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=fake_npc, target=office_pin +[BreakEscape] NPC not found: fake_npc +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_locked_door_cannot_be_bypassed_with_method='unlocked' +--------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.762252"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.762169"], ["updated_at", "2025-11-25 16:20:28.762169"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: unlocked +[BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED door: office_pin +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_NPC_can_unlock_door_if_player_has_encountered_them_and_NPC_has_permission +------------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.764642"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.764573"], ["updated_at", "2025-11-25 16:20:28.764573"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:20:28.765213"], ["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-25 16:20:28 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin +[BreakEscape] NPC unlock validated: helper_npc can unlock office_pin + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:20:28.766897"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlocked_door:_should_grant_access_without_validation +----------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.768318"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.768255"], ["updated_at", "2025-11-25 16:20:28.768255"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=false, lockType=, requires= +[BreakEscape] Door is unlocked in scenario data, granting access + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:20:28.769993"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_password_lock:_empty_attempt_should_fail +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.771415"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.771355"], ["updated_at", "2025-11-25 16:20:28.771355"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_unlock_response_should_filter_requires_from_contents +-------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.773563"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.773501"], ["updated_at", "2025-11-25 16:20:28.773501"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:20:28.775156"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_unlockable_is_not_an_array +-------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.776303"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.776241"], ["updated_at", "2025-11-25 16:20:28.776241"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:20:28.776815"], ["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-25 16:20:28 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlocked_container:_should_grant_access_without_validation +---------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.778850"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.778789"], ["updated_at", "2025-11-25 16:20:28.778789"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:20:28.780491"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_containers +----------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.781940"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.781876"], ["updated_at", "2025-11-25 16:20:28.781876"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:20:28.784451"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.2ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_RFID_lock:_should_trust_client_validation +-------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.785898"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.785833"], ["updated_at", "2025-11-25 16:20:28.785833"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"door_rfid", "attempt"=>nil, "method"=>"rfid", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:20:28.787680"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlock_non-existent_object_should_fail +-------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.789033"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.788972"], ["updated_at", "2025-11-25 16:20:28.788972"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_container_with_password_lock:_correct_password_should_unlock +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.791230"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.791170"], ["updated_at", "2025-11-25 16:20:28.791170"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"secret123", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:20:28.792917"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_locked_container_cannot_be_bypassed_with_method='unlocked' +-------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.794283"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.794135"], ["updated_at", "2025-11-25 16:20:28.794135"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_already-unlocked_container_accepts_method='unlocked' +---------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.796509"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.796448"], ["updated_at", "2025-11-25 16:20:28.796448"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:20:28.797138"], ["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-25 16:20:28 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) 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-25 16:20:28.798784"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"npc_safe", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_bluetooth_lock:_should_trust_client_validation +------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.801526"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.801435"], ["updated_at", "2025-11-25 16:20:28.801435"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"terminal_bluetooth", "attempt"=>nil, "method"=>"bluetooth", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:20:28.803164"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_multiple_unlock_attempts_should_update_state_correctly +------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:20:28.804446"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.804382"], ["updated_at", "2025-11-25 16:20:28.804382"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:20:28.806204"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:20:28.807918"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:20:28.809589"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::MissionTest: test_published_scope_returns_only_published_missions +------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? AND "break_escape_missions"."id" = ? LIMIT ? [["published", 1], ["id", 418560898], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 636030761], ["LIMIT", 1]] + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? AND "break_escape_missions"."id" = ? LIMIT ? [["published", 1], ["id", 636030761], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------- +BreakEscape::MissionTest: test_scenario_path_returns_correct_path +----------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------- +BreakEscape::MissionTest: test_should_validate_uniqueness_of_name +----------------------------------------------------------------- + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Exists? (0.1ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" = ? LIMIT ? [["name", "test"], ["LIMIT", 1]] + BreakEscape::Mission Create (0.0ms) INSERT INTO "break_escape_missions" ("name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at", "secgen_scenario", "collection") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["name", "test"], ["display_name", "Test"], ["description", nil], ["published", 0], ["difficulty_level", 1], ["created_at", "2025-11-25 16:20:28.812022"], ["updated_at", "2025-11-25 16:20:28.812022"], ["secgen_scenario", nil], ["collection", "default"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" = ? LIMIT ? [["name", "test"], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------- +BreakEscape::MissionTest: test_should_validate_presence_of_name +--------------------------------------------------------------- + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" IS NULL LIMIT ? [["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_index_should_display_published_missions +--------------------------------------------------------------------------------- +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.0ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" = ? [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.2ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 6.0ms | GC: 0.2ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 6.2ms | GC: 0.2ms) +Completed 200 OK in 7ms (Views: 6.3ms | ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 0.2ms) + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_show_published_mission +----------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] +Started GET "/break_escape/missions/418560898" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::MissionsController#show as HTML + Parameters: {"id"=>"418560898"} + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."player_type" = ? AND "break_escape_games"."player_id" = ? AND "break_escape_games"."mission_id" = ? LIMIT ? [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) 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", "{\"scenario_brief\":\"Hi! You are a cyber investigator tasked with uncovering evidence of corporate espionage. Anonymous tips suggest the CEO has been selling company secrets, but you need proof.\",\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office1\"},\"npcs\":[{\"id\":\"neye_eve\",\"displayName\":\"Neye Eve\",\"storyPath\":\"scenarios/ink/neye-eve.json\",\"avatar\":\"assets/npc/avatars/npc_adversary.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\"},{\"id\":\"gossip_girl\",\"displayName\":\"Gossip Girl\",\"storyPath\":\"scenarios/ink/gossip-girl.json\",\"avatar\":\"assets/npc/avatars/npc_neutral.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"timedMessages\":[{\"delay\":5000,\"message\":\"Hey! 👋 Got any juicy gossip for me today?\",\"type\":\"text\"}]},{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"storyPath\":\"scenarios/ink/helper-npc.json\",\"avatar\":\"assets/npc/avatars/npc_helper.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"unlockable\":[\"secure_vault\",\"ceo\"],\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":15000},{\"eventPattern\":\"door_unlocked\",\"targetKnot\":\"on_door_unlocked\",\"cooldown\":8000},{\"eventPattern\":\"door_unlock_attempt\",\"targetKnot\":\"on_door_attempt\",\"cooldown\":12000},{\"eventPattern\":\"object_interacted\",\"targetKnot\":\"on_ceo_desk_interact\",\"condition\":\"data.objectType === 'desk_ceo'\",\"cooldown\":10000},{\"eventPattern\":\"item_picked_up:*\",\"targetKnot\":\"on_item_found\",\"cooldown\":20000},{\"eventPattern\":\"room_entered\",\"targetKnot\":\"on_room_entered\",\"cooldown\":45000,\"maxTriggers\":3},{\"eventPattern\":\"room_discovered\",\"targetKnot\":\"on_room_discovered\",\"cooldown\":15000,\"maxTriggers\":5},{\"eventPattern\":\"room_entered:ceo\",\"targetKnot\":\"on_ceo_office_entered\",\"onceOnly\":true}]}],\"objects\":[{\"type\":\"phone\",\"name\":\"Reception Phone\",\"takeable\":false,\"readable\":true,\"voice\":\"Hi, this is the IT Team. Security breach detected in server room. Changed access code to 4829.\",\"sender\":\"IT Team\",\"timestamp\":\"2:15 AM\",\"observations\":\"The reception phone's message light is blinking urgently\"},{\"type\":\"notes\",\"name\":\"Security Log\",\"takeable\":true,\"readable\":true,\"text\":\"Unusual after-hours access detected:\\n- CEO office: 11:30 PM\\n- Server room: 2:15 AM\\n- CEO office again: 3:45 AM\",\"observations\":\"A concerning security log from last night\"},{\"type\":\"pc\",\"name\":\"Reception Computer\",\"takeable\":false,\"lockType\":\"password\",\"passwordHint\":\"Optional hint text\",\"showHint\":true,\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"requires\":\"secret123\",\"observations\":\"The reception's computer, currently locked\",\"postitNote\":\"Password: secret123\",\"showPostit\":true,\"contents\":[{\"type\":\"text_file\",\"name\":\"Private\",\"takeable\":false,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\"}]},{\"type\":\"tablet\",\"name\":\"Tablet Device\",\"takeable\":true,\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"A locked tablet device that requires Bluetooth pairing\"},{\"type\":\"bluetooth_scanner\",\"name\":\"Bluetooth Scanner\",\"takeable\":true,\"observations\":\"A device for detecting nearby Bluetooth signals\",\"canScanBluetooth\":true},{\"type\":\"key\",\"name\":\"Office Key\",\"takeable\":true,\"key_id\":\"office1_key\",\"keyPins\":[65,25,65,25],\"observations\":\"A key to access the office areas\"},{\"type\":\"pin-cracker\",\"name\":\"PIN Cracker\",\"takeable\":true,\"observations\":\"A sophisticated device that can analyze PIN entry patterns and provide feedback on attempts\"},{\"type\":\"safe\",\"name\":\"Reception Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9573\",\"observations\":\"A small wall safe behind the reception desk. Looks like it needs a 4-digit code.\",\"contents\":[{\"type\":\"notes\",\"name\":\"IT Access Credentials\",\"takeable\":true,\"readable\":true,\"text\":\"Emergency IT Admin Credentials:\\nUsername: admin\\nPassword: ITsecure2024\\n\\nServer Room Backup Code: 4829\\nCEO Office Alarm Override: 1337\",\"observations\":\"Sensitive IT credentials that could be very useful\"}]}]},\"office1\":{\"type\":\"room_office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office1_key\",\"keyPins\":[65,25,65,25],\"difficulty\":\"easy\",\"door_sign\":\"4A Hot Desks\",\"connections\":{\"north\":[\"office2\",\"office3\"],\"south\":\"reception\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"requires\":\"password\",\"hasFingerprint\":true,\"fingerprintOwner\":\"ceo\",\"fingerprintDifficulty\":\"medium\",\"observations\":\"A computer with a cybersecurity alert on screen. There might be fingerprints on the keyboard.\"},{\"type\":\"notes\",\"name\":\"IT Memo\",\"takeable\":true,\"readable\":true,\"text\":\"URGENT: Multiple unauthorized access attempts detected from CEO's office IP address\",\"observations\":\"A concerning IT department memo\"},{\"type\":\"fingerprint_kit\",\"name\":\"Fingerprint Kit\",\"takeable\":true,\"observations\":\"A kit used for collecting fingerprints from surfaces\"}]},\"office2\":{\"type\":\"room_office\",\"connections\":{\"north\":\"ceo\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"office2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: office2024\",\"showPostit\":true,\"observations\":\"A standard office computer with a sticky note on the monitor\"},{\"type\":\"notes\",\"name\":\"Shredded Document\",\"takeable\":true,\"readable\":true,\"text\":\"Partially readable: '...offshore account...transfer complete...delete all traces...'\",\"observations\":\"A partially shredded document that someone failed to dispose of properly\"},{\"type\":\"key\",\"name\":\"CEO Office Key\",\"takeable\":true,\"key_id\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"observations\":\"A spare key to the CEO's office, carelessly left behind\"}]},\"office3\":{\"type\":\"room_office\",\"connections\":{\"north\":\"server1\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"IT Staff Computer\",\"takeable\":false,\"requires\":\"bluetooth\",\"lockType\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"An IT staff computer showing network security logs\"},{\"type\":\"notes\",\"name\":\"Network Logs\",\"takeable\":true,\"readable\":true,\"text\":\"Large data transfers detected to unknown external IPs - All originating from CEO's office\",\"observations\":\"Suspicious network activity logs\"}]},\"ceo\":{\"type\":\"room_ceo\",\"connections\":{\"north\":\"closet\",\"south\":\"office2\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"difficulty\":\"easy\",\"objects\":[{\"type\":\"pc\",\"name\":\"CEO Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"ceo2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: ceo2024\",\"showPostit\":true,\"observations\":\"The CEO's laptop, still warm - recently used. A sticky note is attached to the screen.\"},{\"type\":\"suitcase\",\"name\":\"CEO Briefcase\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"difficulty\":\"medium\",\"observations\":\"An expensive leather briefcase with a sturdy lock\",\"contents\":[{\"type\":\"notes\",\"name\":\"Private Note\",\"takeable\":true,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\",\"observations\":\"A hastily written note on expensive paper\"},{\"type\":\"key\",\"name\":\"Safe Key\",\"takeable\":true,\"key_id\":\"safe_key\",\"keyPins\":[52,29,44,37],\"observations\":\"A heavy-duty safe key hidden behind server equipment\"}]},{\"type\":\"phone\",\"name\":\"CEO Phone\",\"takeable\":false,\"readable\":true,\"text\":\"Recent calls: 'Offshore Bank', 'Unknown', 'Data Buyer'\",\"sender\":\"Call Log\",\"timestamp\":\"Last 24 hours\",\"observations\":\"The CEO's phone shows suspicious recent calls\"}]},\"closet\":{\"type\":\"room_closet\",\"connections\":{\"south\":\"ceo\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"7391\",\"objects\":[{\"type\":\"safe\",\"name\":\"Hidden Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"safe_key\",\"keyPins\":[52,29,44,37],\"difficulty\":\"hard\",\"observations\":\"A well-hidden wall safe behind a painting\",\"contents\":[{\"type\":\"notes\",\"name\":\"Incriminating Documents\",\"takeable\":true,\"readable\":true,\"text\":\"Contract for sale of proprietary technology\\nBank transfers from competing companies\\nDetails of upcoming corporate espionage operations\",\"observations\":\"A folder containing damning evidence of corporate espionage. Congratulations! You've recovered the incriminating documents. flag{ceo_exfil_flag}\"}]}]},\"server1\":{\"type\":\"room_servers\",\"connections\":{\"south\":\"office3\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"4829\",\"objects\":[{\"type\":\"pc\",\"name\":\"Server Terminal\",\"takeable\":false,\"observations\":\"The main server terminal showing massive data exfiltration\"},{\"type\":\"key\",\"name\":\"Briefcase Key\",\"takeable\":true,\"key_id\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.824927"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.824288"], ["updated_at", "2025-11-25 16:20:28.824288"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Redirected to http://www.example.com/break_escape/games/1 +Completed 302 Found in 2ms (ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------ +BreakEscape::MissionsControllerTest: test_index_should_return_HTML_with_mission_list +------------------------------------------------------------------------------------ +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.0ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" = ? [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 0.5ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.6ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.7ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_get_index +---------------------------------------------------------- +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.0ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" = ? [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 0.5ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.5ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.6ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_create_game_and_redirect_when_showing_mission +---------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Count (0.0ms) SELECT COUNT(*) FROM "break_escape_games" +Started GET "/break_escape/missions/418560898" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::MissionsController#show as HTML + Parameters: {"id"=>"418560898"} + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."player_type" = ? AND "break_escape_games"."player_id" = ? AND "break_escape_games"."mission_id" = ? LIMIT ? [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) 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", "{\"scenario_brief\":\"Hi! You are a cyber investigator tasked with uncovering evidence of corporate espionage. Anonymous tips suggest the CEO has been selling company secrets, but you need proof.\",\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office1\"},\"npcs\":[{\"id\":\"neye_eve\",\"displayName\":\"Neye Eve\",\"storyPath\":\"scenarios/ink/neye-eve.json\",\"avatar\":\"assets/npc/avatars/npc_adversary.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\"},{\"id\":\"gossip_girl\",\"displayName\":\"Gossip Girl\",\"storyPath\":\"scenarios/ink/gossip-girl.json\",\"avatar\":\"assets/npc/avatars/npc_neutral.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"timedMessages\":[{\"delay\":5000,\"message\":\"Hey! 👋 Got any juicy gossip for me today?\",\"type\":\"text\"}]},{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"storyPath\":\"scenarios/ink/helper-npc.json\",\"avatar\":\"assets/npc/avatars/npc_helper.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"unlockable\":[\"secure_vault\",\"ceo\"],\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":15000},{\"eventPattern\":\"door_unlocked\",\"targetKnot\":\"on_door_unlocked\",\"cooldown\":8000},{\"eventPattern\":\"door_unlock_attempt\",\"targetKnot\":\"on_door_attempt\",\"cooldown\":12000},{\"eventPattern\":\"object_interacted\",\"targetKnot\":\"on_ceo_desk_interact\",\"condition\":\"data.objectType === 'desk_ceo'\",\"cooldown\":10000},{\"eventPattern\":\"item_picked_up:*\",\"targetKnot\":\"on_item_found\",\"cooldown\":20000},{\"eventPattern\":\"room_entered\",\"targetKnot\":\"on_room_entered\",\"cooldown\":45000,\"maxTriggers\":3},{\"eventPattern\":\"room_discovered\",\"targetKnot\":\"on_room_discovered\",\"cooldown\":15000,\"maxTriggers\":5},{\"eventPattern\":\"room_entered:ceo\",\"targetKnot\":\"on_ceo_office_entered\",\"onceOnly\":true}]}],\"objects\":[{\"type\":\"phone\",\"name\":\"Reception Phone\",\"takeable\":false,\"readable\":true,\"voice\":\"Hi, this is the IT Team. Security breach detected in server room. Changed access code to 4829.\",\"sender\":\"IT Team\",\"timestamp\":\"2:15 AM\",\"observations\":\"The reception phone's message light is blinking urgently\"},{\"type\":\"notes\",\"name\":\"Security Log\",\"takeable\":true,\"readable\":true,\"text\":\"Unusual after-hours access detected:\\n- CEO office: 11:30 PM\\n- Server room: 2:15 AM\\n- CEO office again: 3:45 AM\",\"observations\":\"A concerning security log from last night\"},{\"type\":\"pc\",\"name\":\"Reception Computer\",\"takeable\":false,\"lockType\":\"password\",\"passwordHint\":\"Optional hint text\",\"showHint\":true,\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"requires\":\"secret123\",\"observations\":\"The reception's computer, currently locked\",\"postitNote\":\"Password: secret123\",\"showPostit\":true,\"contents\":[{\"type\":\"text_file\",\"name\":\"Private\",\"takeable\":false,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\"}]},{\"type\":\"tablet\",\"name\":\"Tablet Device\",\"takeable\":true,\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"A locked tablet device that requires Bluetooth pairing\"},{\"type\":\"bluetooth_scanner\",\"name\":\"Bluetooth Scanner\",\"takeable\":true,\"observations\":\"A device for detecting nearby Bluetooth signals\",\"canScanBluetooth\":true},{\"type\":\"key\",\"name\":\"Office Key\",\"takeable\":true,\"key_id\":\"office1_key\",\"keyPins\":[65,25,65,25],\"observations\":\"A key to access the office areas\"},{\"type\":\"pin-cracker\",\"name\":\"PIN Cracker\",\"takeable\":true,\"observations\":\"A sophisticated device that can analyze PIN entry patterns and provide feedback on attempts\"},{\"type\":\"safe\",\"name\":\"Reception Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9573\",\"observations\":\"A small wall safe behind the reception desk. Looks like it needs a 4-digit code.\",\"contents\":[{\"type\":\"notes\",\"name\":\"IT Access Credentials\",\"takeable\":true,\"readable\":true,\"text\":\"Emergency IT Admin Credentials:\\nUsername: admin\\nPassword: ITsecure2024\\n\\nServer Room Backup Code: 4829\\nCEO Office Alarm Override: 1337\",\"observations\":\"Sensitive IT credentials that could be very useful\"}]}]},\"office1\":{\"type\":\"room_office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office1_key\",\"keyPins\":[65,25,65,25],\"difficulty\":\"easy\",\"door_sign\":\"4A Hot Desks\",\"connections\":{\"north\":[\"office2\",\"office3\"],\"south\":\"reception\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"requires\":\"password\",\"hasFingerprint\":true,\"fingerprintOwner\":\"ceo\",\"fingerprintDifficulty\":\"medium\",\"observations\":\"A computer with a cybersecurity alert on screen. There might be fingerprints on the keyboard.\"},{\"type\":\"notes\",\"name\":\"IT Memo\",\"takeable\":true,\"readable\":true,\"text\":\"URGENT: Multiple unauthorized access attempts detected from CEO's office IP address\",\"observations\":\"A concerning IT department memo\"},{\"type\":\"fingerprint_kit\",\"name\":\"Fingerprint Kit\",\"takeable\":true,\"observations\":\"A kit used for collecting fingerprints from surfaces\"}]},\"office2\":{\"type\":\"room_office\",\"connections\":{\"north\":\"ceo\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"office2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: office2024\",\"showPostit\":true,\"observations\":\"A standard office computer with a sticky note on the monitor\"},{\"type\":\"notes\",\"name\":\"Shredded Document\",\"takeable\":true,\"readable\":true,\"text\":\"Partially readable: '...offshore account...transfer complete...delete all traces...'\",\"observations\":\"A partially shredded document that someone failed to dispose of properly\"},{\"type\":\"key\",\"name\":\"CEO Office Key\",\"takeable\":true,\"key_id\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"observations\":\"A spare key to the CEO's office, carelessly left behind\"}]},\"office3\":{\"type\":\"room_office\",\"connections\":{\"north\":\"server1\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"IT Staff Computer\",\"takeable\":false,\"requires\":\"bluetooth\",\"lockType\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"An IT staff computer showing network security logs\"},{\"type\":\"notes\",\"name\":\"Network Logs\",\"takeable\":true,\"readable\":true,\"text\":\"Large data transfers detected to unknown external IPs - All originating from CEO's office\",\"observations\":\"Suspicious network activity logs\"}]},\"ceo\":{\"type\":\"room_ceo\",\"connections\":{\"north\":\"closet\",\"south\":\"office2\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"difficulty\":\"easy\",\"objects\":[{\"type\":\"pc\",\"name\":\"CEO Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"ceo2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: ceo2024\",\"showPostit\":true,\"observations\":\"The CEO's laptop, still warm - recently used. A sticky note is attached to the screen.\"},{\"type\":\"suitcase\",\"name\":\"CEO Briefcase\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"difficulty\":\"medium\",\"observations\":\"An expensive leather briefcase with a sturdy lock\",\"contents\":[{\"type\":\"notes\",\"name\":\"Private Note\",\"takeable\":true,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\",\"observations\":\"A hastily written note on expensive paper\"},{\"type\":\"key\",\"name\":\"Safe Key\",\"takeable\":true,\"key_id\":\"safe_key\",\"keyPins\":[52,29,44,37],\"observations\":\"A heavy-duty safe key hidden behind server equipment\"}]},{\"type\":\"phone\",\"name\":\"CEO Phone\",\"takeable\":false,\"readable\":true,\"text\":\"Recent calls: 'Offshore Bank', 'Unknown', 'Data Buyer'\",\"sender\":\"Call Log\",\"timestamp\":\"Last 24 hours\",\"observations\":\"The CEO's phone shows suspicious recent calls\"}]},\"closet\":{\"type\":\"room_closet\",\"connections\":{\"south\":\"ceo\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"7391\",\"objects\":[{\"type\":\"safe\",\"name\":\"Hidden Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"safe_key\",\"keyPins\":[52,29,44,37],\"difficulty\":\"hard\",\"observations\":\"A well-hidden wall safe behind a painting\",\"contents\":[{\"type\":\"notes\",\"name\":\"Incriminating Documents\",\"takeable\":true,\"readable\":true,\"text\":\"Contract for sale of proprietary technology\\nBank transfers from competing companies\\nDetails of upcoming corporate espionage operations\",\"observations\":\"A folder containing damning evidence of corporate espionage. Congratulations! You've recovered the incriminating documents. flag{ceo_exfil_flag}\"}]}]},\"server1\":{\"type\":\"room_servers\",\"connections\":{\"south\":\"office3\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"4829\",\"objects\":[{\"type\":\"pc\",\"name\":\"Server Terminal\",\"takeable\":false,\"observations\":\"The main server terminal showing massive data exfiltration\"},{\"type\":\"key\",\"name\":\"Briefcase Key\",\"takeable\":true,\"key_id\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.832091"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.831460"], ["updated_at", "2025-11-25 16:20:28.831460"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Redirected to http://www.example.com/break_escape/games/1 +Completed 302 Found in 2ms (ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Count (0.0ms) SELECT COUNT(*) FROM "break_escape_games" + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------ +BreakEscape::RoomLazyLoadTest: test_room_response_includes_all_room_data +------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.834172"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.834131"], ["updated_at", "2025-11-25 16:20:28.834131"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/room/test_room" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#room as HTML + Parameters: {"id"=>"1", "room_id"=>"test_room"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Serving room data for: test_room +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::RoomLazyLoadTest: test_should_return_400_when_room_id_is_missing +----------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.836463"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.836431"], ["updated_at", "2025-11-25 16:20:28.836431"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::RoomLazyLoadTest: test_should_return_room_data_for_valid_room_id +----------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.837474"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.837444"], ["updated_at", "2025-11-25 16:20:28.837444"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/room/test_room" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#room as HTML + Parameters: {"id"=>"1", "room_id"=>"test_room"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Serving room data for: test_room +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::RoomLazyLoadTest: test_should_return_404_for_non-existent_room +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.839636"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.839606"], ["updated_at", "2025-11-25 16:20:28.839606"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/room/non_existent_room" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#room as HTML + Parameters: {"id"=>"1", "room_id"=>"non_existent_room"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_baseURL_prevents_duplicate_asset_paths +------------------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_complete_asset_loading_path_for_lockpicking +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/lockpicking-game-phaser.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) +Started GET "/break_escape/assets/sounds/lockpick_click.mp3" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_click.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_click.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_overtension.mp3" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_overtension.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_overtension.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_reset.mp3" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_reset.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_reset.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_set.mp3" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_set.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_set.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_success.mp3" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_success.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_success.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_tension.mp3" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_tension.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_tension.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_wrong.mp3" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_wrong.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_wrong.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_load_all_required_game_files_in_correct_order +--------------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_lockpicking_minigame +-------------------------------------------------------------------------------- +Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/lockpicking-game-phaser.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_all_response_headers_are_correct +------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_door_tile_image +--------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door.png" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_game_core_with_asset_references +------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_security:_cannot_access_files_outside_break_escape_directory +----------------------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/../../config/secrets.yml" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/secrets.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.2ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/js/../../config/database.yml" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/database.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.2ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.2ms) +Started GET "/break_escape/assets/../../config/secrets.yml" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/secrets.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_test_asset_page_loads_correctly +------------------------------------------------------------------------------ +Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as HTML + Parameters: {"filename"=>"test-assets"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/test-assets.html (0.1ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_CSS_files_should_be_accessible_from_main_game +-------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_minigame_starters +----------------------------------------------------------------------------- +Started GET "/break_escape/js/systems/minigame-starters.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/minigame-starters.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/minigame-starters.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_route_constraints_correctly_capture_file_extensions +-------------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_should_load_GAME_CONFIG_with_proper_baseURL +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_key-operations_minigame_module +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/minigames/lockpicking/key-operations.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/key-operations.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/key-operations.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_asset_paths_work_without_assets_prefix_in_load_calls +--------------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_sound_manager_module +-------------------------------------------------------------------------------- +Started GET "/break_escape/js/systems/sound-manager.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/sound-manager.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/sound-manager.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------- +BreakEscapeTest: test_it_has_a_version_number +--------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Assets:_should_return_404_for_non-existent_files +--------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/non-existent.mp3" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/non-existent.mp3"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_CSS_files_are_non-empty +------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Routes:_should_handle_files_with_multiple_dots +------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door_sheet_32.png" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_sheet_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_sheet_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Minigame:_should_serve_lockpicking_script +-------------------------------------------------------------------------------------- +Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/lockpicking-game-phaser.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Phaser:_game.js_has_asset_references_without_prefix +------------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_JS:_should_serve_nested_files +-------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_CSS:_should_serve_files_with_correct_MIME_type +------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_audio_files_are_non-empty +--------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Headers:_should_include_Content-Length +----------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_image_files_are_non-empty +--------------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_CSS:_should_return_404_for_non-existent_files +------------------------------------------------------------------------------------------ +Started GET "/break_escape/css/non-existent.css" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"non-existent.css"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Routes:_should_capture_complex_paths_with_segments +----------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Phaser:_constants_define_GAME_CONFIG_with_baseURL +---------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_JS:_should_serve_core_game_module +------------------------------------------------------------------------------ +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Security:_should_prevent_directory_traversal_in_CSS +------------------------------------------------------------------------------------------------ +Started GET "/break_escape/css/../../config/database.yml" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/database.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Assets:_should_serve_audio_with_correct_MIME_type +---------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Assets:_should_serve_nested_files +------------------------------------------------------------------------------ +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_HTML:_should_serve_test_files_with_correct_MIME_type +------------------------------------------------------------------------------------------------- +Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as HTML + Parameters: {"filename"=>"test-assets"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/test-assets.html (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Assets:_should_serve_PNG_tiles_with_correct_MIME_type +-------------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.1ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Phaser:_main_JS_imports_GAME_CONFIG +-------------------------------------------------------------------------------- +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_JavaScript_files_are_non-empty +-------------------------------------------------------------------------------------- +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_CSS:_should_serve_with_inline_disposition +-------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Security:_should_prevent_directory_traversal_in_JS +----------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/../../config/secrets.yml" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/secrets.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Headers:_should_include_Cache-Control +---------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_JS:_should_return_404_for_non-existent_files +----------------------------------------------------------------------------------------- +Started GET "/break_escape/js/non-existent.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"non-existent.js"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Routes:_should_capture_full_filename_with_extension +------------------------------------------------------------------------------------------------ +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Minigame:_should_serve_lockpicking_sounds +-------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_click.mp3" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_click.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_click.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_success.mp3" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_success.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_success.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_HTML:_should_return_404_for_non-existent_files +------------------------------------------------------------------------------------------- +Started GET "/break_escape/non-existent.html" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 + +ActionController::RoutingError (No route matches [GET] "/break_escape/non-existent.html"): + + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Headers:_should_set_Content-Disposition_to_inline +---------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_JS:_should_serve_files_with_correct_MIME_type +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Security:_should_prevent_directory_traversal_in_assets +--------------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/../../config/database.yml" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/database.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_does_not_modify_original +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.924097"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.924039"], ["updated_at", "2025-11-25 16:20:28.924039"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_removes_room_contents +--------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.925225"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.925177"], ["updated_at", "2025-11-25 16:20:28.925177"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_preserves_lock_requirements +--------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.926291"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.926252"], ["updated_at", "2025-11-25 16:20:28.926252"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_removes_objects_and_npcs +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.927240"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.927202"], ["updated_at", "2025-11-25 16:20:28.927202"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------------ +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_preserves_navigation_structure +------------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.928252"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.928214"], ["updated_at", "2025-11-25 16:20:28.928214"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_inventory_endpoint_should_add_items +-------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"keypad\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.929435"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.929402"], ["updated_at", "2025-11-25 16:20:28.929402"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/inventory" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#inventory as HTML + Parameters: {"action_type"=>"add", "item"=>{"type"=>"lockpick", "name"=>"Lockpick", "id"=>"lockpick_1"}, "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] inventory endpoint: action=add, item=#"lockpick", "name"=>"Lockpick", "id"=>"lockpick_1"} permitted: false> +[BreakEscape] validate_item_collectible: type=lockpick, id=lockpick_1, name=Lockpick +[BreakEscape] Item not found in scenario: lockpick +[BreakEscape] inventory validation failed: Item not found in scenario: lockpick +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_show_should_inject_game_configuration +---------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"keypad\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.932000"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.931963"], ["updated_at", "2025-11-25 16:20:28.931963"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.5ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.5ms | GC: 0.0ms) +Completed 200 OK in 2ms (Views: 0.7ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_unlock_endpoint_should_accept_correct_keypad_code +---------------------------------------------------------------------------------------- + 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.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"keypad\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.935501"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.935467"], ["updated_at", "2025-11-25 16:20:28.935467"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"room", "targetId"=>"office", "attempt"=>"1234", "method"=>"keypad", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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=room, id=office, attempt=1234, method=keypad +[BreakEscape] Object not found: office +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_scenario_endpoint_should_return_JSON +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"keypad\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.937725"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.937686"], ["updated_at", "2025-11-25 16:20:28.937686"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#scenario as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_unlock_endpoint_should_reject_invalid_attempts +------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"keypad\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.939770"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.939737"], ["updated_at", "2025-11-25 16:20:28.939737"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"room", "targetId"=>"office", "attempt"=>"wrong_code", "method"=>"keypad", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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=room, id=office, attempt=wrong_code, method=keypad +[BreakEscape] Object not found: office +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::GamesControllerTest: test_ink_endpoint_should_return_404_for_NPC_without_story_file +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"keypad\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.941785"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.941752"], ["updated_at", "2025-11-25 16:20:28.941752"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=missing-npc" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"missing-npc", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: missing-npc +[BreakEscape] No NPCs found in scenario data +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_ink_endpoint_should_require_npc_parameter +-------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"keypad\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.943799"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.943767"], ["updated_at", "2025-11-25 16:20:28.943767"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 400 Bad Request in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_sync_state_should_update_player_state_for_current_room +--------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"keypad\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.945810"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.945777"], ["updated_at", "2025-11-25 16:20:28.945777"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#sync_state as HTML + Parameters: {"currentRoom"=>"reception", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------- +BreakEscape::GamesControllerTest: test_should_show_game +------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"keypad\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.948455"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.948419"], ["updated_at", "2025-11-25 16:20:28.948419"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.2ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.2ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.3ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_show_should_return_HTML_with_game_container +---------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"keypad\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.951293"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.951257"], ["updated_at", "2025-11-25 16:20:28.951257"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.1ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.2ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.3ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::GamesControllerTest: test_ink_endpoint_should_return_404_for_non-existent_NPC +------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"keypad\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:20:28.954289"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:20:28.954254"], ["updated_at", "2025-11-25 16:20:28.954254"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=non-existent" for 127.0.0.1 at 2025-11-25 16:20:28 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"non-existent", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: non-existent +[BreakEscape] No NPCs found in scenario data +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_JSON_content_type +----------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_WOFF_font_content_type +---------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_TTF_font_content_type +--------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_JPEG_content_type +----------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_is_case_insensitive +-------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_GIF_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_WOFF2_font_content_type +----------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_PNG_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_returns_octet-stream_for_unknown_extensions +-------------------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_MP3_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_HTML_content_type +----------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_SVG_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_CSS_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_handles_multiple_dots_in_filename +---------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_JavaScript_content_type +----------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_OGG_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_WAV_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + ActiveRecord::InternalMetadata Load (0.1ms) 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.0ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC + TRANSACTION (0.0ms) begin transaction +  (0.1ms) PRAGMA foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys = ON +  (0.0ms) PRAGMA foreign_keys = OFF + Fixtures Load (0.1ms) 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-25 16:21:08', '2025-11-25 16:21:08'); +INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-25 16:21:08', '2025-11-25 16:21:08'); +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-25 16:21:08', '2025-11-25 16:21:08'); +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-25 16:21:08', '2025-11-25 16:21:08') +  (0.0ms) PRAGMA defer_foreign_keys = 0 +  (0.0ms) PRAGMA foreign_keys = 1 + TRANSACTION (1.3ms) commit transaction +  (0.0ms) PRAGMA foreign_key_check + TRANSACTION (0.0ms) begin transaction +---------------------------------------------- +BreakEscape::GameTest: test_should_unlock_room +---------------------------------------------- + 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.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.555081"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.555004"], ["updated_at", "2025-11-25 16:21:08.555004"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\",\"office\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:21:08.555839"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::GameTest: test_should_allow_access_to_unlocked_doors_regardless_of_method +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.556996"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.556967"], ["updated_at", "2025-11-25 16:21:08.556967"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=reception, attempt=, method=unlocked +[BreakEscape] Door already unlocked in player state, granting access + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------- +BreakEscape::GameTest: test_key_takes_precedence_over_lockpick_attempt +---------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.558032"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.558002"], ["updated_at", "2025-11-25 16:21:08.558002"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=key +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office1_key in inventory (2 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=true +[BreakEscape] Key office1_key found in inventory: true +[BreakEscape] Key validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------ +BreakEscape::GameTest: test_should_update_health +------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.559069"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.559041"], ["updated_at", "2025-11-25 16:21:08.559041"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":50}"], ["updated_at", "2025-11-25 16:21:08.559579"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GameTest: test_has_key_in_inventory_should_find_keys_by_key_id +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.560754"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.560724"], ["updated_at", "2025-11-25 16:21:08.560724"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Checking for key office1_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=true +[BreakEscape] Key office1_key found in inventory: true +[BreakEscape] Checking for key wrong_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=false +[BreakEscape] Key wrong_key found in inventory: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------- +BreakEscape::GameTest: test_should_validate_unlock_with_correct_key +------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.562035"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.562004"], ["updated_at", "2025-11-25 16:21:08.562004"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=key +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office1_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=true +[BreakEscape] Key office1_key found in inventory: true +[BreakEscape] Key validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------- +BreakEscape::GameTest: test_should_validate_unlock_with_lockpick +---------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.563164"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.563135"], ["updated_at", "2025-11-25 16:21:08.563135"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=lockpick +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: lockpick +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=lockpick, scenarioData.type=, is_lockpick=true +[BreakEscape] Lockpick found in inventory: true +[BreakEscape] Lockpick validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------- +BreakEscape::GameTest: test_should_clamp_health_between_0_and_100 +----------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.564429"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.564399"], ["updated_at", "2025-11-25 16:21:08.564399"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":0}"], ["updated_at", "2025-11-25 16:21:08.565054"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------- +BreakEscape::GameTest: test_has_lockpick_in_inventory_should_not_find_non-lockpick_items +---------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.565985"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.565955"], ["updated_at", "2025-11-25 16:21:08.565955"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=key, scenarioData.type=, is_lockpick=false +[BreakEscape] Lockpick found in inventory: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::GameTest: test_should_reject_locked_door_without_any_unlock_method +------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.567053"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.567025"], ["updated_at", "2025-11-25 16:21:08.567025"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method= +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: +[BreakEscape] SECURITY VIOLATION: No valid unlock method for LOCKED door: office1, method= +[BreakEscape] validate_unlock returning: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------- +BreakEscape::GameTest: test_should_reject_lockpick_unlock_without_lockpick_in_inventory +--------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.568068"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.568039"], ["updated_at", "2025-11-25 16:21:08.568039"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=lockpick +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: lockpick +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=key, scenarioData.type=, is_lockpick=false +[BreakEscape] Lockpick found in inventory: false +[BreakEscape] Lockpick validation result: false +[BreakEscape] validate_unlock returning: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------ +BreakEscape::GameTest: test_lockpick_should_bypass_key_requirement +------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.569069"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.569040"], ["updated_at", "2025-11-25 16:21:08.569040"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=secure_vault, attempt=, method=lockpick +[BreakEscape] Room data: locked=true, lockType=key, requires=vault_master_key +[BreakEscape] Room is LOCKED, method must be valid: lockpick +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=lockpick, scenarioData.type=, is_lockpick=true +[BreakEscape] Lockpick found in inventory: true +[BreakEscape] Lockpick validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------- +BreakEscape::GameTest: test_should_track_inventory +-------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.570112"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.570086"], ["updated_at", "2025-11-25 16:21:08.570086"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"key\",\"name\":\"Test Key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:21:08.570606"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GameTest: test_has_lockpick_in_inventory_should_find_lockpicks +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.571583"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.571552"], ["updated_at", "2025-11-25 16:21:08.571552"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=lockpick, scenarioData.type=, is_lockpick=true +[BreakEscape] Lockpick found in inventory: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------- +BreakEscape::GameTest: test_should_belong_to_player_and_mission +--------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.572615"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.572586"], ["updated_at", "2025-11-25 16:21:08.572586"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------- +BreakEscape::GameTest: test_should_reject_unlock_without_required_key +--------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.573553"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.573526"], ["updated_at", "2025-11-25 16:21:08.573526"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=key +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office1_key in inventory (1 items) +[BreakEscape] Inventory item: name=Wrong Key, key_id=wrong_key, is_match=false +[BreakEscape] Key office1_key found in inventory: false +[BreakEscape] Key validation result: false +[BreakEscape] validate_unlock returning: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) 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.0ms) 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.1ms) 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-25 16:21:08.587190"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.587101"], ["updated_at", "2025-11-25 16:21:08.587101"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_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\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:21:08.587857"], ["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-25 16:21:08 +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.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=fake_npc, target=office_pin +[BreakEscape] NPC not found: fake_npc +Completed 422 Unprocessable Content in 3ms (Views: 0.1ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_locked_door_cannot_be_bypassed_with_method='unlocked' +--------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.603846"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.603767"], ["updated_at", "2025-11-25 16:21:08.603767"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: unlocked +[BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED door: office_pin +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_incorrect_PIN_should_fail +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.606653"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.606585"], ["updated_at", "2025-11-25 16:21:08.606585"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) 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.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.609129"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.609066"], ["updated_at", "2025-11-25 16:21:08.609066"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:21:08.609904"], ["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-25 16:21:08 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:21:08.612150"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 2ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_lockpick:_should_trust_client_validation +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.613742"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.613673"], ["updated_at", "2025-11-25 16:21:08.613673"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"box_lockpick", "attempt"=>nil, "method"=>"lockpick", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) 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-25 16:21:08.615631"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_unlockable_is_not_an_array +-------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.616988"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.616917"], ["updated_at", "2025-11-25 16:21:08.616917"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:21:08.617606"], ["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-25 16:21:08 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_player_has_not_encountered_NPC +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.619766"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.619700"], ["updated_at", "2025-11-25 16:21:08.619700"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:21:08.620298"], ["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-25 16:21:08 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin +[BreakEscape] Player has not encountered NPC: helper_npc +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_biometric_lock:_should_trust_client_validation +------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.622599"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.622529"], ["updated_at", "2025-11-25 16:21:08.622529"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"scanner_biometric", "attempt"=>nil, "method"=>"biometric", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:21:08.624286"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_password_lock:_correct_password_should_unlock +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.625477"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.625412"], ["updated_at", "2025-11-25 16:21:08.625412"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:21:08.627351"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlocked_door:_should_grant_access_without_validation +----------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.628938"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.628861"], ["updated_at", "2025-11-25 16:21:08.628861"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=false, lockType=, requires= +[BreakEscape] Door is unlocked in scenario data, granting access + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:21:08.630820"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_locked_container_cannot_be_bypassed_with_method='unlocked' +-------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.632340"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.632274"], ["updated_at", "2025-11-25 16:21:08.632274"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlock_non-existent_object_should_fail +-------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.634818"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.634753"], ["updated_at", "2025-11-25 16:21:08.634753"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_already-unlocked_container_accepts_method='unlocked' +---------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.637074"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.637008"], ["updated_at", "2025-11-25 16:21:08.637008"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:21:08.637643"], ["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-25 16:21:08 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:21:08.639230"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"npc_safe", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_container_with_password_lock:_correct_password_should_unlock +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.641899"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.641836"], ["updated_at", "2025-11-25 16:21:08.641836"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"secret123", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:21:08.643704"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlocked_container:_should_grant_access_without_validation +---------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.645206"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.645140"], ["updated_at", "2025-11-25 16:21:08.645140"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:21:08.647086"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_NPC_unlock_adds_door_to_unlockedRooms +------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.648560"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.648496"], ["updated_at", "2025-11-25 16:21:08.648496"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:21:08.649138"], ["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-25 16:21:08 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (1.8ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin +[BreakEscape] NPC unlock validated: helper_npc can unlock office_pin + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:21:08.652594"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 3ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 1.7ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_key_lock:_should_trust_client_validation +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.654277"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.654210"], ["updated_at", "2025-11-25 16:21:08.654210"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"drawer_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:21:08.656123"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlock_with_invalid_method_should_fail +-------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.657451"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.657389"], ["updated_at", "2025-11-25 16:21:08.657389"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: invalid_method +[BreakEscape] SECURITY VIOLATION: No valid unlock method for LOCKED door: office_pin, method=invalid_method +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_correct_PIN_should_unlock +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.659745"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.659644"], ["updated_at", "2025-11-25 16:21:08.659644"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:21:08.661495"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.1ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) 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.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.663393"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.663323"], ["updated_at", "2025-11-25 16:21:08.663323"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:21:08.664005"], ["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-25 16:21:08 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_password_lock:_empty_attempt_should_fail +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.2ms) 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-25 16:21:08.666726"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.666659"], ["updated_at", "2025-11-25 16:21:08.666659"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_password_lock:_incorrect_password_should_fail +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.2ms) 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-25 16:21:08.669047"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.668984"], ["updated_at", "2025-11-25 16:21:08.668984"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"wrongpassword", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: false +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_containers +----------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.671273"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.671143"], ["updated_at", "2025-11-25 16:21:08.671143"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:21:08.672910"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_NPC_can_unlock_door_if_player_has_encountered_them_and_NPC_has_permission +------------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.674138"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.674003"], ["updated_at", "2025-11-25 16:21:08.674003"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:21:08.674667"], ["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-25 16:21:08 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin +[BreakEscape] NPC unlock validated: helper_npc can unlock office_pin + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:21:08.676334"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlock_same_door_twice_should_be_idempotent +------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.677744"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.677675"], ["updated_at", "2025-11-25 16:21:08.677675"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:21:08.679637"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_incorrect_PIN_should_fail +--------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.682796"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.682661"], ["updated_at", "2025-11-25 16:21:08.682661"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: false +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_RFID_lock:_should_trust_client_validation +-------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.685228"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.685154"], ["updated_at", "2025-11-25 16:21:08.685154"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"door_rfid", "attempt"=>nil, "method"=>"rfid", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:21:08.686784"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_multiple_unlock_attempts_should_update_state_correctly +------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.688023"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.687962"], ["updated_at", "2025-11-25 16:21:08.687962"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 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\",\"office_pin\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:21:08.690357"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 3ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 1.3ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.3ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:21:08.696132"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.9ms (5 queries, 0 cached) | GC: 2.8ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) 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.0ms) 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-25 16:21:08.701926"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 4ms (Views: 0.0ms | ActiveRecord: 0.6ms (5 queries, 0 cached) | GC: 2.9ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_doors +------------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.706529"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.706061"], ["updated_at", "2025-11-25 16:21:08.706061"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) 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.0ms) 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] Room data: locked=false, lockType=, requires= +[BreakEscape] Door is unlocked in scenario data, granting access + TRANSACTION (0.0ms) 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\",\"office_unlocked\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:21:08.712036"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 2.3ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_key_lock:_should_trust_client_validation +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.716154"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.716084"], ["updated_at", "2025-11-25 16:21:08.716084"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_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\":[],\"inventory\":[{\"id\":\"office_key\",\"type\":\"key\",\"name\":\"Office Key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:21:08.717591"], ["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-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=key, requires=office_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=, is_match=true +[BreakEscape] Key office_key found in inventory: true +[BreakEscape] Key validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_key\"],\"unlockedObjects\":[],\"inventory\":[{\"id\":\"office_key\",\"type\":\"key\",\"name\":\"Office Key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:21:08.720814"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 2ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.2ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_unlock_response_should_not_expose_'requires'_field_for_exploitable_locks +----------------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.722436"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.722238"], ["updated_at", "2025-11-25 16:21:08.722238"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:21:08.724254"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_bluetooth_lock:_should_trust_client_validation +------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.725499"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.725373"], ["updated_at", "2025-11-25 16:21:08.725373"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"terminal_bluetooth", "attempt"=>nil, "method"=>"bluetooth", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:21:08.727317"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_correct_PIN_should_unlock +--------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.728586"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.728465"], ["updated_at", "2025-11-25 16:21:08.728465"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:21:08.730490"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_unlock_response_should_filter_requires_from_contents +-------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.731994"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.731918"], ["updated_at", "2025-11-25 16:21:08.731918"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:21:08.733807"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_already-unlocked_door_accepts_method='unlocked' +----------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.735109"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.735046"], ["updated_at", "2025-11-25 16:21:08.735046"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:21:08.735637"], ["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-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"ceo", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=password, requires=TopSecret123 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=ceo +[BreakEscape] NPC unlock validated: helper_npc can unlock ceo + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:21:08.737310"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"ceo", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_password_lock:_case_sensitivity +----------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.739991"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.739928"], ["updated_at", "2025-11-25 16:21:08.739928"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"OpenSesame", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: false +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_unlock_non-existent_door_should_fail +------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:21:08.742263"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.742199"], ["updated_at", "2025-11-25 16:21:08.742199"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------- +BreakEscapeTest: test_it_has_a_version_number +--------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_does_not_modify_original +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.745109"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.745057"], ["updated_at", "2025-11-25 16:21:08.745057"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_removes_objects_and_npcs +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.746216"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.746174"], ["updated_at", "2025-11-25 16:21:08.746174"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_preserves_lock_requirements +--------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.747322"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.747282"], ["updated_at", "2025-11-25 16:21:08.747282"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_removes_room_contents +--------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.748363"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.748323"], ["updated_at", "2025-11-25 16:21:08.748323"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------------ +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_preserves_navigation_structure +------------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.749363"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.749322"], ["updated_at", "2025-11-25 16:21:08.749322"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_returns_octet-stream_for_unknown_extensions +-------------------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_is_case_insensitive +-------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_JSON_content_type +----------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_JPEG_content_type +----------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_MP3_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_JavaScript_content_type +----------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_handles_multiple_dots_in_filename +---------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_GIF_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_CSS_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_WAV_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_TTF_font_content_type +--------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_OGG_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_HTML_content_type +----------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_PNG_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_SVG_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_WOFF_font_content_type +---------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_WOFF2_font_content_type +----------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_lockpicking_minigame +-------------------------------------------------------------------------------- +Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/lockpicking-game-phaser.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js (1.0ms) +Completed 200 OK in 1ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_route_constraints_correctly_capture_file_extensions +-------------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_baseURL_prevents_duplicate_asset_paths +------------------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_minigame_starters +----------------------------------------------------------------------------- +Started GET "/break_escape/js/systems/minigame-starters.js" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/minigame-starters.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/minigame-starters.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_CSS_files_should_be_accessible_from_main_game +-------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_sound_manager_module +-------------------------------------------------------------------------------- +Started GET "/break_escape/js/systems/sound-manager.js" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/sound-manager.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/sound-manager.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_test_asset_page_loads_correctly +------------------------------------------------------------------------------ +Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as HTML + Parameters: {"filename"=>"test-assets"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/test-assets.html (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_should_load_GAME_CONFIG_with_proper_baseURL +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_asset_paths_work_without_assets_prefix_in_load_calls +--------------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_load_all_required_game_files_in_correct_order +--------------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_door_tile_image +--------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door.png" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_complete_asset_loading_path_for_lockpicking +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/lockpicking-game-phaser.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_click.mp3" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_click.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_click.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_overtension.mp3" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_overtension.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_overtension.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_reset.mp3" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_reset.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_reset.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_set.mp3" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_set.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_set.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_success.mp3" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_success.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_success.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_tension.mp3" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_tension.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_tension.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_wrong.mp3" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_wrong.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_wrong.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_key-operations_minigame_module +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/minigames/lockpicking/key-operations.js" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/key-operations.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/key-operations.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_all_response_headers_are_correct +------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.2ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_security:_cannot_access_files_outside_break_escape_directory +----------------------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/../../config/secrets.yml" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/secrets.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 1ms (Views: 1.3ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) +Started GET "/break_escape/js/../../config/database.yml" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/database.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/../../config/secrets.yml" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/secrets.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_game_core_with_asset_references +------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::GamesControllerTest: test_ink_endpoint_should_return_404_for_non-existent_NPC +------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.778021"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.777962"], ["updated_at", "2025-11-25 16:21:08.777962"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=non-existent" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"non-existent", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: non-existent +[BreakEscape] No NPCs found in scenario data +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_ink_endpoint_should_require_npc_parameter +-------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.780759"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.780706"], ["updated_at", "2025-11-25 16:21:08.780706"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 400 Bad Request in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_unlock_endpoint_should_accept_correct_pin_code +------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.783097"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.783055"], ["updated_at", "2025-11-25 16:21:08.783055"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"room", "targetId"=>"office", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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=room, id=office, attempt=1234, method=pin +[BreakEscape] Object not found: office +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_sync_state_should_update_player_state_for_current_room +--------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.785427"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.785388"], ["updated_at", "2025-11-25 16:21:08.785388"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#sync_state as HTML + Parameters: {"currentRoom"=>"reception", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------- +BreakEscape::GamesControllerTest: test_should_show_game +------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.788025"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.787988"], ["updated_at", "2025-11-25 16:21:08.787988"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 1.5ms | GC: 0.1ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 1.7ms | GC: 0.1ms) +Completed 200 OK in 3ms (Views: 1.9ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_scenario_endpoint_should_return_JSON +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.2ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.793266"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.793227"], ["updated_at", "2025-11-25 16:21:08.793227"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#scenario as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_inventory_endpoint_should_add_items +-------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.795627"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.795588"], ["updated_at", "2025-11-25 16:21:08.795588"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/inventory" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#inventory as HTML + Parameters: {"action_type"=>"add", "item"=>{"type"=>"lockpick", "name"=>"Lockpick", "id"=>"lockpick_1"}, "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] inventory endpoint: action=add, item=#"lockpick", "name"=>"Lockpick", "id"=>"lockpick_1"} permitted: false> +[BreakEscape] validate_item_collectible: type=lockpick, id=lockpick_1, name=Lockpick +[BreakEscape] Item is a starting item, skipping room/container checks +[BreakEscape] Adding item to inventory: lockpick / Lockpick + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) 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\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true},{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:21:08.797433"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Item added successfully. Current inventory: [{"type"=>"lockpick", "name"=>"Lockpick", "id"=>"lockpick_1", "takeable"=>true}, {"type"=>"lockpick", "name"=>"Lockpick", "id"=>"lockpick_1"}] +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_show_should_return_HTML_with_game_container +---------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.798795"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.798756"], ["updated_at", "2025-11-25 16:21:08.798756"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"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.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.2ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.2ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.3ms | ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::GamesControllerTest: test_ink_endpoint_should_return_404_for_NPC_without_story_file +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.802047"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.802008"], ["updated_at", "2025-11-25 16:21:08.802008"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=missing-npc" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"missing-npc", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: missing-npc +[BreakEscape] No NPCs found in scenario data +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_show_should_inject_game_configuration +---------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.804245"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.804207"], ["updated_at", "2025-11-25 16:21:08.804207"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.1ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.2ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.3ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_unlock_endpoint_should_reject_invalid_attempts +------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.807068"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.807028"], ["updated_at", "2025-11-25 16:21:08.807028"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"room", "targetId"=>"office", "attempt"=>"wrong_code", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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=room, id=office, attempt=wrong_code, method=pin +[BreakEscape] Object not found: office +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_index_should_display_published_missions +--------------------------------------------------------------------------------- +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.0ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" = ? [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.2ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 5.9ms | GC: 0.1ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 6.0ms | GC: 0.1ms) +Completed 200 OK in 7ms (Views: 5.9ms | ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_get_index +---------------------------------------------------------- +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.0ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" = ? [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 0.6ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.7ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.7ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------ +BreakEscape::MissionsControllerTest: test_index_should_return_HTML_with_mission_list +------------------------------------------------------------------------------------ +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.0ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" = ? [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 0.5ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.6ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.6ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_show_published_mission +----------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] +Started GET "/break_escape/missions/418560898" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::MissionsController#show as HTML + Parameters: {"id"=>"418560898"} + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."player_type" = ? AND "break_escape_games"."player_id" = ? AND "break_escape_games"."mission_id" = ? LIMIT ? [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) 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", "{\"scenario_brief\":\"Hi! You are a cyber investigator tasked with uncovering evidence of corporate espionage. Anonymous tips suggest the CEO has been selling company secrets, but you need proof.\",\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office1\"},\"npcs\":[{\"id\":\"neye_eve\",\"displayName\":\"Neye Eve\",\"storyPath\":\"scenarios/ink/neye-eve.json\",\"avatar\":\"assets/npc/avatars/npc_adversary.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\"},{\"id\":\"gossip_girl\",\"displayName\":\"Gossip Girl\",\"storyPath\":\"scenarios/ink/gossip-girl.json\",\"avatar\":\"assets/npc/avatars/npc_neutral.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"timedMessages\":[{\"delay\":5000,\"message\":\"Hey! 👋 Got any juicy gossip for me today?\",\"type\":\"text\"}]},{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"storyPath\":\"scenarios/ink/helper-npc.json\",\"avatar\":\"assets/npc/avatars/npc_helper.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"unlockable\":[\"secure_vault\",\"ceo\"],\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":15000},{\"eventPattern\":\"door_unlocked\",\"targetKnot\":\"on_door_unlocked\",\"cooldown\":8000},{\"eventPattern\":\"door_unlock_attempt\",\"targetKnot\":\"on_door_attempt\",\"cooldown\":12000},{\"eventPattern\":\"object_interacted\",\"targetKnot\":\"on_ceo_desk_interact\",\"condition\":\"data.objectType === 'desk_ceo'\",\"cooldown\":10000},{\"eventPattern\":\"item_picked_up:*\",\"targetKnot\":\"on_item_found\",\"cooldown\":20000},{\"eventPattern\":\"room_entered\",\"targetKnot\":\"on_room_entered\",\"cooldown\":45000,\"maxTriggers\":3},{\"eventPattern\":\"room_discovered\",\"targetKnot\":\"on_room_discovered\",\"cooldown\":15000,\"maxTriggers\":5},{\"eventPattern\":\"room_entered:ceo\",\"targetKnot\":\"on_ceo_office_entered\",\"onceOnly\":true}]}],\"objects\":[{\"type\":\"phone\",\"name\":\"Reception Phone\",\"takeable\":false,\"readable\":true,\"voice\":\"Hi, this is the IT Team. Security breach detected in server room. Changed access code to 4829.\",\"sender\":\"IT Team\",\"timestamp\":\"2:15 AM\",\"observations\":\"The reception phone's message light is blinking urgently\"},{\"type\":\"notes\",\"name\":\"Security Log\",\"takeable\":true,\"readable\":true,\"text\":\"Unusual after-hours access detected:\\n- CEO office: 11:30 PM\\n- Server room: 2:15 AM\\n- CEO office again: 3:45 AM\",\"observations\":\"A concerning security log from last night\"},{\"type\":\"pc\",\"name\":\"Reception Computer\",\"takeable\":false,\"lockType\":\"password\",\"passwordHint\":\"Optional hint text\",\"showHint\":true,\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"requires\":\"secret123\",\"observations\":\"The reception's computer, currently locked\",\"postitNote\":\"Password: secret123\",\"showPostit\":true,\"contents\":[{\"type\":\"text_file\",\"name\":\"Private\",\"takeable\":false,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\"}]},{\"type\":\"tablet\",\"name\":\"Tablet Device\",\"takeable\":true,\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"A locked tablet device that requires Bluetooth pairing\"},{\"type\":\"bluetooth_scanner\",\"name\":\"Bluetooth Scanner\",\"takeable\":true,\"observations\":\"A device for detecting nearby Bluetooth signals\",\"canScanBluetooth\":true},{\"type\":\"key\",\"name\":\"Office Key\",\"takeable\":true,\"key_id\":\"office1_key\",\"keyPins\":[65,25,65,25],\"observations\":\"A key to access the office areas\"},{\"type\":\"pin-cracker\",\"name\":\"PIN Cracker\",\"takeable\":true,\"observations\":\"A sophisticated device that can analyze PIN entry patterns and provide feedback on attempts\"},{\"type\":\"safe\",\"name\":\"Reception Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9573\",\"observations\":\"A small wall safe behind the reception desk. Looks like it needs a 4-digit code.\",\"contents\":[{\"type\":\"notes\",\"name\":\"IT Access Credentials\",\"takeable\":true,\"readable\":true,\"text\":\"Emergency IT Admin Credentials:\\nUsername: admin\\nPassword: ITsecure2024\\n\\nServer Room Backup Code: 4829\\nCEO Office Alarm Override: 1337\",\"observations\":\"Sensitive IT credentials that could be very useful\"}]}]},\"office1\":{\"type\":\"room_office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office1_key\",\"keyPins\":[65,25,65,25],\"difficulty\":\"easy\",\"door_sign\":\"4A Hot Desks\",\"connections\":{\"north\":[\"office2\",\"office3\"],\"south\":\"reception\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"requires\":\"password\",\"hasFingerprint\":true,\"fingerprintOwner\":\"ceo\",\"fingerprintDifficulty\":\"medium\",\"observations\":\"A computer with a cybersecurity alert on screen. There might be fingerprints on the keyboard.\"},{\"type\":\"notes\",\"name\":\"IT Memo\",\"takeable\":true,\"readable\":true,\"text\":\"URGENT: Multiple unauthorized access attempts detected from CEO's office IP address\",\"observations\":\"A concerning IT department memo\"},{\"type\":\"fingerprint_kit\",\"name\":\"Fingerprint Kit\",\"takeable\":true,\"observations\":\"A kit used for collecting fingerprints from surfaces\"}]},\"office2\":{\"type\":\"room_office\",\"connections\":{\"north\":\"ceo\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"office2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: office2024\",\"showPostit\":true,\"observations\":\"A standard office computer with a sticky note on the monitor\"},{\"type\":\"notes\",\"name\":\"Shredded Document\",\"takeable\":true,\"readable\":true,\"text\":\"Partially readable: '...offshore account...transfer complete...delete all traces...'\",\"observations\":\"A partially shredded document that someone failed to dispose of properly\"},{\"type\":\"key\",\"name\":\"CEO Office Key\",\"takeable\":true,\"key_id\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"observations\":\"A spare key to the CEO's office, carelessly left behind\"}]},\"office3\":{\"type\":\"room_office\",\"connections\":{\"north\":\"server1\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"IT Staff Computer\",\"takeable\":false,\"requires\":\"bluetooth\",\"lockType\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"An IT staff computer showing network security logs\"},{\"type\":\"notes\",\"name\":\"Network Logs\",\"takeable\":true,\"readable\":true,\"text\":\"Large data transfers detected to unknown external IPs - All originating from CEO's office\",\"observations\":\"Suspicious network activity logs\"}]},\"ceo\":{\"type\":\"room_ceo\",\"connections\":{\"north\":\"closet\",\"south\":\"office2\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"difficulty\":\"easy\",\"objects\":[{\"type\":\"pc\",\"name\":\"CEO Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"ceo2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: ceo2024\",\"showPostit\":true,\"observations\":\"The CEO's laptop, still warm - recently used. A sticky note is attached to the screen.\"},{\"type\":\"suitcase\",\"name\":\"CEO Briefcase\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"difficulty\":\"medium\",\"observations\":\"An expensive leather briefcase with a sturdy lock\",\"contents\":[{\"type\":\"notes\",\"name\":\"Private Note\",\"takeable\":true,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\",\"observations\":\"A hastily written note on expensive paper\"},{\"type\":\"key\",\"name\":\"Safe Key\",\"takeable\":true,\"key_id\":\"safe_key\",\"keyPins\":[52,29,44,37],\"observations\":\"A heavy-duty safe key hidden behind server equipment\"}]},{\"type\":\"phone\",\"name\":\"CEO Phone\",\"takeable\":false,\"readable\":true,\"text\":\"Recent calls: 'Offshore Bank', 'Unknown', 'Data Buyer'\",\"sender\":\"Call Log\",\"timestamp\":\"Last 24 hours\",\"observations\":\"The CEO's phone shows suspicious recent calls\"}]},\"closet\":{\"type\":\"room_closet\",\"connections\":{\"south\":\"ceo\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"7391\",\"objects\":[{\"type\":\"safe\",\"name\":\"Hidden Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"safe_key\",\"keyPins\":[52,29,44,37],\"difficulty\":\"hard\",\"observations\":\"A well-hidden wall safe behind a painting\",\"contents\":[{\"type\":\"notes\",\"name\":\"Incriminating Documents\",\"takeable\":true,\"readable\":true,\"text\":\"Contract for sale of proprietary technology\\nBank transfers from competing companies\\nDetails of upcoming corporate espionage operations\",\"observations\":\"A folder containing damning evidence of corporate espionage. Congratulations! You've recovered the incriminating documents. flag{ceo_exfil_flag}\"}]}]},\"server1\":{\"type\":\"room_servers\",\"connections\":{\"south\":\"office3\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"4829\",\"objects\":[{\"type\":\"pc\",\"name\":\"Server Terminal\",\"takeable\":false,\"observations\":\"The main server terminal showing massive data exfiltration\"},{\"type\":\"key\",\"name\":\"Briefcase Key\",\"takeable\":true,\"key_id\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.823660"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.822977"], ["updated_at", "2025-11-25 16:21:08.822977"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Redirected to http://www.example.com/break_escape/games/1 +Completed 302 Found in 2ms (ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_create_game_and_redirect_when_showing_mission +---------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Count (0.0ms) SELECT COUNT(*) FROM "break_escape_games" +Started GET "/break_escape/missions/418560898" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::MissionsController#show as HTML + Parameters: {"id"=>"418560898"} + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."player_type" = ? AND "break_escape_games"."player_id" = ? AND "break_escape_games"."mission_id" = ? LIMIT ? [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) 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", "{\"scenario_brief\":\"Hi! You are a cyber investigator tasked with uncovering evidence of corporate espionage. Anonymous tips suggest the CEO has been selling company secrets, but you need proof.\",\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office1\"},\"npcs\":[{\"id\":\"neye_eve\",\"displayName\":\"Neye Eve\",\"storyPath\":\"scenarios/ink/neye-eve.json\",\"avatar\":\"assets/npc/avatars/npc_adversary.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\"},{\"id\":\"gossip_girl\",\"displayName\":\"Gossip Girl\",\"storyPath\":\"scenarios/ink/gossip-girl.json\",\"avatar\":\"assets/npc/avatars/npc_neutral.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"timedMessages\":[{\"delay\":5000,\"message\":\"Hey! 👋 Got any juicy gossip for me today?\",\"type\":\"text\"}]},{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"storyPath\":\"scenarios/ink/helper-npc.json\",\"avatar\":\"assets/npc/avatars/npc_helper.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"unlockable\":[\"secure_vault\",\"ceo\"],\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":15000},{\"eventPattern\":\"door_unlocked\",\"targetKnot\":\"on_door_unlocked\",\"cooldown\":8000},{\"eventPattern\":\"door_unlock_attempt\",\"targetKnot\":\"on_door_attempt\",\"cooldown\":12000},{\"eventPattern\":\"object_interacted\",\"targetKnot\":\"on_ceo_desk_interact\",\"condition\":\"data.objectType === 'desk_ceo'\",\"cooldown\":10000},{\"eventPattern\":\"item_picked_up:*\",\"targetKnot\":\"on_item_found\",\"cooldown\":20000},{\"eventPattern\":\"room_entered\",\"targetKnot\":\"on_room_entered\",\"cooldown\":45000,\"maxTriggers\":3},{\"eventPattern\":\"room_discovered\",\"targetKnot\":\"on_room_discovered\",\"cooldown\":15000,\"maxTriggers\":5},{\"eventPattern\":\"room_entered:ceo\",\"targetKnot\":\"on_ceo_office_entered\",\"onceOnly\":true}]}],\"objects\":[{\"type\":\"phone\",\"name\":\"Reception Phone\",\"takeable\":false,\"readable\":true,\"voice\":\"Hi, this is the IT Team. Security breach detected in server room. Changed access code to 4829.\",\"sender\":\"IT Team\",\"timestamp\":\"2:15 AM\",\"observations\":\"The reception phone's message light is blinking urgently\"},{\"type\":\"notes\",\"name\":\"Security Log\",\"takeable\":true,\"readable\":true,\"text\":\"Unusual after-hours access detected:\\n- CEO office: 11:30 PM\\n- Server room: 2:15 AM\\n- CEO office again: 3:45 AM\",\"observations\":\"A concerning security log from last night\"},{\"type\":\"pc\",\"name\":\"Reception Computer\",\"takeable\":false,\"lockType\":\"password\",\"passwordHint\":\"Optional hint text\",\"showHint\":true,\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"requires\":\"secret123\",\"observations\":\"The reception's computer, currently locked\",\"postitNote\":\"Password: secret123\",\"showPostit\":true,\"contents\":[{\"type\":\"text_file\",\"name\":\"Private\",\"takeable\":false,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\"}]},{\"type\":\"tablet\",\"name\":\"Tablet Device\",\"takeable\":true,\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"A locked tablet device that requires Bluetooth pairing\"},{\"type\":\"bluetooth_scanner\",\"name\":\"Bluetooth Scanner\",\"takeable\":true,\"observations\":\"A device for detecting nearby Bluetooth signals\",\"canScanBluetooth\":true},{\"type\":\"key\",\"name\":\"Office Key\",\"takeable\":true,\"key_id\":\"office1_key\",\"keyPins\":[65,25,65,25],\"observations\":\"A key to access the office areas\"},{\"type\":\"pin-cracker\",\"name\":\"PIN Cracker\",\"takeable\":true,\"observations\":\"A sophisticated device that can analyze PIN entry patterns and provide feedback on attempts\"},{\"type\":\"safe\",\"name\":\"Reception Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9573\",\"observations\":\"A small wall safe behind the reception desk. Looks like it needs a 4-digit code.\",\"contents\":[{\"type\":\"notes\",\"name\":\"IT Access Credentials\",\"takeable\":true,\"readable\":true,\"text\":\"Emergency IT Admin Credentials:\\nUsername: admin\\nPassword: ITsecure2024\\n\\nServer Room Backup Code: 4829\\nCEO Office Alarm Override: 1337\",\"observations\":\"Sensitive IT credentials that could be very useful\"}]}]},\"office1\":{\"type\":\"room_office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office1_key\",\"keyPins\":[65,25,65,25],\"difficulty\":\"easy\",\"door_sign\":\"4A Hot Desks\",\"connections\":{\"north\":[\"office2\",\"office3\"],\"south\":\"reception\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"requires\":\"password\",\"hasFingerprint\":true,\"fingerprintOwner\":\"ceo\",\"fingerprintDifficulty\":\"medium\",\"observations\":\"A computer with a cybersecurity alert on screen. There might be fingerprints on the keyboard.\"},{\"type\":\"notes\",\"name\":\"IT Memo\",\"takeable\":true,\"readable\":true,\"text\":\"URGENT: Multiple unauthorized access attempts detected from CEO's office IP address\",\"observations\":\"A concerning IT department memo\"},{\"type\":\"fingerprint_kit\",\"name\":\"Fingerprint Kit\",\"takeable\":true,\"observations\":\"A kit used for collecting fingerprints from surfaces\"}]},\"office2\":{\"type\":\"room_office\",\"connections\":{\"north\":\"ceo\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"office2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: office2024\",\"showPostit\":true,\"observations\":\"A standard office computer with a sticky note on the monitor\"},{\"type\":\"notes\",\"name\":\"Shredded Document\",\"takeable\":true,\"readable\":true,\"text\":\"Partially readable: '...offshore account...transfer complete...delete all traces...'\",\"observations\":\"A partially shredded document that someone failed to dispose of properly\"},{\"type\":\"key\",\"name\":\"CEO Office Key\",\"takeable\":true,\"key_id\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"observations\":\"A spare key to the CEO's office, carelessly left behind\"}]},\"office3\":{\"type\":\"room_office\",\"connections\":{\"north\":\"server1\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"IT Staff Computer\",\"takeable\":false,\"requires\":\"bluetooth\",\"lockType\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"An IT staff computer showing network security logs\"},{\"type\":\"notes\",\"name\":\"Network Logs\",\"takeable\":true,\"readable\":true,\"text\":\"Large data transfers detected to unknown external IPs - All originating from CEO's office\",\"observations\":\"Suspicious network activity logs\"}]},\"ceo\":{\"type\":\"room_ceo\",\"connections\":{\"north\":\"closet\",\"south\":\"office2\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"difficulty\":\"easy\",\"objects\":[{\"type\":\"pc\",\"name\":\"CEO Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"ceo2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: ceo2024\",\"showPostit\":true,\"observations\":\"The CEO's laptop, still warm - recently used. A sticky note is attached to the screen.\"},{\"type\":\"suitcase\",\"name\":\"CEO Briefcase\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"difficulty\":\"medium\",\"observations\":\"An expensive leather briefcase with a sturdy lock\",\"contents\":[{\"type\":\"notes\",\"name\":\"Private Note\",\"takeable\":true,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\",\"observations\":\"A hastily written note on expensive paper\"},{\"type\":\"key\",\"name\":\"Safe Key\",\"takeable\":true,\"key_id\":\"safe_key\",\"keyPins\":[52,29,44,37],\"observations\":\"A heavy-duty safe key hidden behind server equipment\"}]},{\"type\":\"phone\",\"name\":\"CEO Phone\",\"takeable\":false,\"readable\":true,\"text\":\"Recent calls: 'Offshore Bank', 'Unknown', 'Data Buyer'\",\"sender\":\"Call Log\",\"timestamp\":\"Last 24 hours\",\"observations\":\"The CEO's phone shows suspicious recent calls\"}]},\"closet\":{\"type\":\"room_closet\",\"connections\":{\"south\":\"ceo\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"7391\",\"objects\":[{\"type\":\"safe\",\"name\":\"Hidden Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"safe_key\",\"keyPins\":[52,29,44,37],\"difficulty\":\"hard\",\"observations\":\"A well-hidden wall safe behind a painting\",\"contents\":[{\"type\":\"notes\",\"name\":\"Incriminating Documents\",\"takeable\":true,\"readable\":true,\"text\":\"Contract for sale of proprietary technology\\nBank transfers from competing companies\\nDetails of upcoming corporate espionage operations\",\"observations\":\"A folder containing damning evidence of corporate espionage. Congratulations! You've recovered the incriminating documents. flag{ceo_exfil_flag}\"}]}]},\"server1\":{\"type\":\"room_servers\",\"connections\":{\"south\":\"office3\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"4829\",\"objects\":[{\"type\":\"pc\",\"name\":\"Server Terminal\",\"takeable\":false,\"observations\":\"The main server terminal showing massive data exfiltration\"},{\"type\":\"key\",\"name\":\"Briefcase Key\",\"takeable\":true,\"key_id\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.826918"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.826267"], ["updated_at", "2025-11-25 16:21:08.826267"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Redirected to http://www.example.com/break_escape/games/1 +Completed 302 Found in 2ms (ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Count (0.0ms) SELECT COUNT(*) FROM "break_escape_games" + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Assets:_should_return_404_for_non-existent_files +--------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/non-existent.mp3" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/non-existent.mp3"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_audio_files_are_non-empty +--------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Security:_should_prevent_directory_traversal_in_CSS +------------------------------------------------------------------------------------------------ +Started GET "/break_escape/css/../../config/database.yml" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/database.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_HTML:_should_return_404_for_non-existent_files +------------------------------------------------------------------------------------------- +Started GET "/break_escape/non-existent.html" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 + +ActionController::RoutingError (No route matches [GET] "/break_escape/non-existent.html"): + + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_CSS:_should_serve_with_inline_disposition +-------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_HTML:_should_serve_test_files_with_correct_MIME_type +------------------------------------------------------------------------------------------------- +Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as HTML + Parameters: {"filename"=>"test-assets"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/test-assets.html (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_CSS:_should_serve_files_with_correct_MIME_type +------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Assets:_should_serve_nested_files +------------------------------------------------------------------------------ +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Headers:_should_set_Content-Disposition_to_inline +---------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_JS:_should_serve_nested_files +-------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Assets:_should_serve_audio_with_correct_MIME_type +---------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_image_files_are_non-empty +--------------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Security:_should_prevent_directory_traversal_in_assets +--------------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/../../config/database.yml" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/database.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Routes:_should_capture_complex_paths_with_segments +----------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Security:_should_prevent_directory_traversal_in_JS +----------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/../../config/secrets.yml" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/secrets.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_CSS:_should_return_404_for_non-existent_files +------------------------------------------------------------------------------------------ +Started GET "/break_escape/css/non-existent.css" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"non-existent.css"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Phaser:_game.js_has_asset_references_without_prefix +------------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Minigame:_should_serve_lockpicking_sounds +-------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_click.mp3" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_click.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_click.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_success.mp3" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_success.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_success.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Headers:_should_include_Cache-Control +---------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Assets:_should_serve_PNG_tiles_with_correct_MIME_type +-------------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Phaser:_main_JS_imports_GAME_CONFIG +-------------------------------------------------------------------------------- +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_JS:_should_return_404_for_non-existent_files +----------------------------------------------------------------------------------------- +Started GET "/break_escape/js/non-existent.js" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"non-existent.js"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Headers:_should_include_Content-Length +----------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_JS:_should_serve_files_with_correct_MIME_type +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_JavaScript_files_are_non-empty +-------------------------------------------------------------------------------------- +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_CSS_files_are_non-empty +------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Minigame:_should_serve_lockpicking_script +-------------------------------------------------------------------------------------- +Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/lockpicking-game-phaser.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Routes:_should_handle_files_with_multiple_dots +------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door_sheet_32.png" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_sheet_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_sheet_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_JS:_should_serve_core_game_module +------------------------------------------------------------------------------ +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Phaser:_constants_define_GAME_CONFIG_with_baseURL +---------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Routes:_should_capture_full_filename_with_extension +------------------------------------------------------------------------------------------------ +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------ +BreakEscape::RoomLazyLoadTest: test_room_response_includes_all_room_data +------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.894304"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.894247"], ["updated_at", "2025-11-25 16:21:08.894247"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/room/test_room" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#room as HTML + Parameters: {"id"=>"1", "room_id"=>"test_room"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Serving room data for: test_room +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::RoomLazyLoadTest: test_should_return_400_when_room_id_is_missing +----------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.897018"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.896976"], ["updated_at", "2025-11-25 16:21:08.896976"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::RoomLazyLoadTest: test_should_return_room_data_for_valid_room_id +----------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.898180"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.898146"], ["updated_at", "2025-11-25 16:21:08.898146"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/room/test_room" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#room as HTML + Parameters: {"id"=>"1", "room_id"=>"test_room"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Serving room data for: test_room +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::RoomLazyLoadTest: test_should_return_404_for_non-existent_room +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.900335"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.900303"], ["updated_at", "2025-11-25 16:21:08.900303"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/room/non_existent_room" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#room as HTML + Parameters: {"id"=>"1", "room_id"=>"non_existent_room"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_404_for_NPC_without_story_file +--------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.902508"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.902473"], ["updated_at", "2025-11-25 16:21:08.902473"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=npc-with-no-file" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"npc-with-no-file", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: npc-with-no-file +[BreakEscape] Available NPCs: security_guard (test_room), test-npc (test_room) +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_person-chat-minigame_should_use_Rails_API_endpoint_for_story_loading +--------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.904563"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.904531"], ["updated_at", "2025-11-25 16:21:08.904531"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/person-chat/person-chat-minigame.js?v=10" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"v"=>"10", "path"=>"minigames/person-chat/person-chat-minigame.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/person-chat/person-chat-minigame.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_npc-lazy-loader_should_construct_correct_API_endpoint_URL +---------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.906315"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.906284"], ["updated_at", "2025-11-25 16:21:08.906284"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/systems/npc-lazy-loader.js" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/npc-lazy-loader.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/npc-lazy-loader.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_bad_request_if_npc_parameter_missing +--------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.907929"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.907889"], ["updated_at", "2025-11-25 16:21:08.907889"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 400 Bad Request in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_ink_endpoint_should_return_application/json_content_type +--------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + TRANSACTION (1.3ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (1.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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.909873"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.909841"], ["updated_at", "2025-11-25 16:21:08.909841"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=security_guard" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"security_guard", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: security_guard +[BreakEscape] Found NPC: security_guard with storyPath: scenarios/ink/security-guard.json +[BreakEscape] Serving ink from: /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/scenarios/ink/security-guard.json +Completed 200 OK in 1ms (Views: 0.4ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.2ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_404_for_non-existent_game +---------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.2ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:08.914817"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:08.914772"], ["updated_at", "2025-11-25 16:21:08.914772"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/999999/ink?npc=test-npc" for 127.0.0.1 at 2025-11-25 16:21:08 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"test-npc", "id"=>"999999"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 999999], ["LIMIT", 1]] +Completed 404 Not Found in 0ms (ActiveRecord: 0.0ms (1 query, 0 cached) | GC: 0.0ms) + +ActiveRecord::RecordNotFound (Couldn't find BreakEscape::Game with 'id'="999999"): + +activerecord (7.2.3) lib/active_record/core.rb:268:in `find' +/home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/controllers/break_escape/games_controller.rb:323:in `set_game' +activesupport (7.2.3) lib/active_support/callbacks.rb:362:in `block in make_lambda' +activesupport (7.2.3) lib/active_support/callbacks.rb:179:in `block in call' +actionpack (7.2.3) lib/abstract_controller/callbacks.rb:34:in `block (2 levels) in ' +activesupport (7.2.3) lib/active_support/callbacks.rb:180:in `call' +activesupport (7.2.3) lib/active_support/callbacks.rb:560:in `block in invoke_before' +activesupport (7.2.3) lib/active_support/callbacks.rb:560:in `each' +activesupport (7.2.3) lib/active_support/callbacks.rb:560:in `invoke_before' +activesupport (7.2.3) lib/active_support/callbacks.rb:119:in `block in run_callbacks' +actiontext (7.2.3) lib/action_text/rendering.rb:25:in `with_renderer' +actiontext (7.2.3) lib/action_text/engine.rb:71:in `block (4 levels) in ' +activesupport (7.2.3) lib/active_support/callbacks.rb:130:in `instance_exec' +activesupport (7.2.3) lib/active_support/callbacks.rb:130:in `block in run_callbacks' +activesupport (7.2.3) lib/active_support/callbacks.rb:141:in `run_callbacks' +actionpack (7.2.3) lib/abstract_controller/callbacks.rb:260:in `process_action' +actionpack (7.2.3) lib/action_controller/metal/rescue.rb:27:in `process_action' +actionpack (7.2.3) lib/action_controller/metal/instrumentation.rb:77:in `block in process_action' +activesupport (7.2.3) lib/active_support/notifications.rb:210:in `block in instrument' +activesupport (7.2.3) lib/active_support/notifications/instrumenter.rb:58:in `instrument' +activesupport (7.2.3) lib/active_support/notifications.rb:210:in `instrument' +actionpack (7.2.3) lib/action_controller/metal/instrumentation.rb:76:in `process_action' +actionpack (7.2.3) lib/action_controller/metal/params_wrapper.rb:259:in `process_action' +activerecord (7.2.3) lib/active_record/railties/controller_runtime.rb:39:in `process_action' +actionpack (7.2.3) lib/abstract_controller/base.rb:152:in `process' +actionview (7.2.3) lib/action_view/rendering.rb:40:in `process' +actionpack (7.2.3) lib/action_controller/metal.rb:252:in `dispatch' +actionpack (7.2.3) lib/action_controller/metal.rb:335:in `dispatch' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:67:in `dispatch' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:50:in `serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:53:in `block in serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:133:in `block in find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `each' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:34:in `serve' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:896:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/static.rb:27:in `call' +railties (7.2.3) lib/rails/engine.rb:535:in `call' +railties (7.2.3) lib/rails/railtie.rb:226:in `public_send' +railties (7.2.3) lib/rails/railtie.rb:226:in `method_missing' +actionpack (7.2.3) lib/action_dispatch/routing/mapper.rb:33:in `block in ' +actionpack (7.2.3) lib/action_dispatch/routing/mapper.rb:62:in `serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:53:in `block in serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:133:in `block in find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `each' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:34:in `serve' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:896:in `call' +rack (3.2.4) lib/rack/tempfile_reaper.rb:20:in `call' +rack (3.2.4) lib/rack/etag.rb:29:in `call' +rack (3.2.4) lib/rack/conditional_get.rb:31:in `call' +rack (3.2.4) lib/rack/head.rb:15:in `call' +actionpack (7.2.3) lib/action_dispatch/http/permissions_policy.rb:38:in `call' +actionpack (7.2.3) lib/action_dispatch/http/content_security_policy.rb:38:in `call' +rack-session (2.1.1) lib/rack/session/abstract/id.rb:274:in `context' +rack-session (2.1.1) lib/rack/session/abstract/id.rb:268:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/cookies.rb:704:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/callbacks.rb:31:in `block in call' +activesupport (7.2.3) lib/active_support/callbacks.rb:101:in `run_callbacks' +actionpack (7.2.3) lib/action_dispatch/middleware/callbacks.rb:30:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/actionable_exceptions.rb:18:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/debug_exceptions.rb:31:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/show_exceptions.rb:32:in `call' +railties (7.2.3) lib/rails/rack/logger.rb:41:in `call_app' +railties (7.2.3) lib/rails/rack/logger.rb:29:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/remote_ip.rb:96:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/request_id.rb:33:in `call' +rack (3.2.4) lib/rack/method_override.rb:28:in `call' +rack (3.2.4) lib/rack/runtime.rb:24:in `call' +activesupport (7.2.3) lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/executor.rb:16:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/static.rb:27:in `call' +rack (3.2.4) lib/rack/sendfile.rb:131:in `call' +railties (7.2.3) lib/rails/engine.rb:535:in `call' +rack-test (2.2.0) lib/rack/test.rb:360:in `process_request' +rack-test (2.2.0) lib/rack/test.rb:153:in `request' +actionpack (7.2.3) lib/action_dispatch/testing/integration.rb:287:in `process' +actionpack (7.2.3) lib/action_dispatch/testing/integration.rb:19:in `get' +actionpack (7.2.3) lib/action_dispatch/testing/integration.rb:378:in `get' +/home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/test/integration/npc_ink_loading_test.rb:155:in `block in ' +minitest (5.26.2) lib/minitest/test.rb:95:in `block (2 levels) in run' +minitest (5.26.2) lib/minitest/test.rb:191:in `capture_exceptions' +minitest (5.26.2) lib/minitest/test.rb:90:in `block in run' +minitest (5.26.2) lib/minitest.rb:383:in `time_it' +minitest (5.26.2) lib/minitest/test.rb:89:in `run' +activesupport (7.2.3) lib/active_support/executor/test_helper.rb:5:in `block in run' +activesupport (7.2.3) lib/active_support/execution_wrapper.rb:104:in `perform' +activesupport (7.2.3) lib/active_support/executor/test_helper.rb:5:in `run' +minitest (5.26.2) lib/minitest.rb:1224:in `run_one_method' +minitest (5.26.2) lib/minitest.rb:463:in `run_one_method' +minitest (5.26.2) lib/minitest.rb:450:in `block (2 levels) in run' +minitest (5.26.2) lib/minitest.rb:446:in `each' +minitest (5.26.2) lib/minitest.rb:446:in `block in run' +minitest (5.26.2) lib/minitest.rb:488:in `on_signal' +minitest (5.26.2) lib/minitest.rb:475:in `with_info_handler' +minitest (5.26.2) lib/minitest.rb:445:in `run' +railties (7.2.3) lib/rails/test_unit/line_filtering.rb:10:in `run' +minitest (5.26.2) lib/minitest.rb:347:in `block in __run' +minitest (5.26.2) lib/minitest.rb:347:in `map' +minitest (5.26.2) lib/minitest.rb:347:in `__run' +minitest (5.26.2) lib/minitest.rb:302:in `run' +minitest (5.26.2) lib/minitest.rb:86:in `block in autorun' + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_phone-chat-minigame_should_use_Rails_API_endpoint_for_story_loading +-------------------------------------------------------------------------------------------------------- + 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.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:09.048501"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:09.048449"], ["updated_at", "2025-11-25 16:21:09.048449"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/phone-chat/phone-chat-minigame.js" for 127.0.0.1 at 2025-11-25 16:21:09 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/phone-chat/phone-chat-minigame.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/phone-chat/phone-chat-minigame.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------ +BreakEscape::NPCInkLoadingTest: test_npc-barks_should_import_ASSETS_PATH_from_config +------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:09.050854"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:09.050813"], ["updated_at", "2025-11-25 16:21:09.050813"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/systems/npc-barks.js" for 127.0.0.1 at 2025-11-25 16:21:09 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/npc-barks.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/npc-barks.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_phone-chat-ui_should_import_ASSETS_PATH_from_config +---------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:09.052728"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:09.052689"], ["updated_at", "2025-11-25 16:21:09.052689"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/phone-chat/phone-chat-ui.js" for 127.0.0.1 at 2025-11-25 16:21:09 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/phone-chat/phone-chat-ui.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/phone-chat/phone-chat-ui.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_npc-manager_should_load_stories_via_API_endpoint +------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:09.054386"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:09.054354"], ["updated_at", "2025-11-25 16:21:09.054354"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/systems/npc-manager.js" for 127.0.0.1 at 2025-11-25 16:21:09 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/npc-manager.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/npc-manager.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_ink_endpoint_should_work_with_underscored_NPC_IDs +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:09.056037"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:09.056005"], ["updated_at", "2025-11-25 16:21:09.056005"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=npc-with-underscores" for 127.0.0.1 at 2025-11-25 16:21:09 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"npc-with-underscores", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: npc-with-underscores +[BreakEscape] Available NPCs: security_guard (test_room), test-npc (test_room) +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::NPCInkLoadingTest: test_person-chat-portraits_should_import_ASSETS_PATH_from_config +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:09.058183"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:09.058151"], ["updated_at", "2025-11-25 16:21:09.058151"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/person-chat/person-chat-portraits.js" for 127.0.0.1 at 2025-11-25 16:21:09 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/person-chat/person-chat-portraits.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/person-chat/person-chat-portraits.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_404_for_non-existent_NPC +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:09.059777"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:09.059741"], ["updated_at", "2025-11-25 16:21:09.059741"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=non-existent-npc" for 127.0.0.1 at 2025-11-25 16:21:09 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"non-existent-npc", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: non-existent-npc +[BreakEscape] Available NPCs: security_guard (test_room), test-npc (test_room) +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::MissionTest: test_published_scope_returns_only_published_missions +------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? AND "break_escape_missions"."id" = ? LIMIT ? [["published", 1], ["id", 418560898], ["LIMIT", 1]] + BreakEscape::Mission Load (0.2ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 636030761], ["LIMIT", 1]] + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? AND "break_escape_missions"."id" = ? LIMIT ? [["published", 1], ["id", 636030761], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------- +BreakEscape::MissionTest: test_scenario_path_returns_correct_path +----------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------- +BreakEscape::MissionTest: test_should_validate_uniqueness_of_name +----------------------------------------------------------------- + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Exists? (0.1ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" = ? LIMIT ? [["name", "test"], ["LIMIT", 1]] + BreakEscape::Mission Create (0.1ms) INSERT INTO "break_escape_missions" ("name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at", "secgen_scenario", "collection") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["name", "test"], ["display_name", "Test"], ["description", nil], ["published", 0], ["difficulty_level", 1], ["created_at", "2025-11-25 16:21:09.063270"], ["updated_at", "2025-11-25 16:21:09.063270"], ["secgen_scenario", nil], ["collection", "default"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" = ? LIMIT ? [["name", "test"], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------- +BreakEscape::MissionTest: test_should_validate_presence_of_name +--------------------------------------------------------------- + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" IS NULL LIMIT ? [["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + ActiveRecord::InternalMetadata Load (0.1ms) 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.0ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC + TRANSACTION (0.0ms) begin transaction +  (0.1ms) PRAGMA foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys = ON +  (0.0ms) PRAGMA foreign_keys = OFF + Fixtures Load (0.1ms) 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-25 16:21:54', '2025-11-25 16:21:54'); +INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-25 16:21:54', '2025-11-25 16:21:54'); +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-25 16:21:54', '2025-11-25 16:21:54'); +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-25 16:21:54', '2025-11-25 16:21:54') +  (0.0ms) PRAGMA defer_foreign_keys = 0 +  (0.0ms) PRAGMA foreign_keys = 1 + TRANSACTION (1.2ms) commit transaction +  (0.0ms) PRAGMA foreign_key_check + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_unlock_endpoint_should_accept_correct_pin_code +------------------------------------------------------------------------------------- + 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.0ms) 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.2ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:21:54.919940"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:21:54.919843"], ["updated_at", "2025-11-25 16:21:54.919843"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:21:54 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"room", "targetId"=>"office", "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.0ms) 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.0ms) 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=room, id=office, attempt=1234, method=pin +[BreakEscape] Object not found: office +Completed 422 Unprocessable Content in 3ms (Views: 0.1ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + ActiveRecord::InternalMetadata Load (0.1ms) 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.0ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC + TRANSACTION (0.0ms) begin transaction +  (0.1ms) PRAGMA foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys = ON +  (0.0ms) PRAGMA foreign_keys = OFF + Fixtures Load (0.1ms) 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-25 16:22:15', '2025-11-25 16:22:15'); +INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-25 16:22:15', '2025-11-25 16:22:15'); +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-25 16:22:15', '2025-11-25 16:22:15'); +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-25 16:22:15', '2025-11-25 16:22:15') +  (0.0ms) PRAGMA defer_foreign_keys = 0 +  (0.0ms) PRAGMA foreign_keys = 1 + TRANSACTION (1.1ms) commit transaction +  (0.0ms) PRAGMA foreign_key_check + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_unlock_endpoint_should_reject_invalid_attempts +------------------------------------------------------------------------------------- + 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:22:15.324061"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:22:15.323977"], ["updated_at", "2025-11-25 16:22:15.323977"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:22:15 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"room", "targetId"=>"office", "attempt"=>"wrong_code", "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.0ms) 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.0ms) 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=room, id=office, attempt=wrong_code, method=pin +[BreakEscape] Object not found: office +Completed 422 Unprocessable Content in 3ms (Views: 0.1ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + ActiveRecord::InternalMetadata Load (0.1ms) 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.0ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC + TRANSACTION (0.0ms) begin transaction +  (0.1ms) PRAGMA foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys = ON +  (0.0ms) PRAGMA foreign_keys = OFF + Fixtures Load (0.1ms) 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-25 16:24:39', '2025-11-25 16:24:39'); +INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-25 16:24:39', '2025-11-25 16:24:39'); +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-25 16:24:39', '2025-11-25 16:24:39'); +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-25 16:24:39', '2025-11-25 16:24:39') +  (0.0ms) PRAGMA defer_foreign_keys = 0 +  (0.0ms) PRAGMA foreign_keys = 1 + TRANSACTION (0.9ms) commit transaction +  (0.0ms) PRAGMA foreign_key_check + TRANSACTION (0.0ms) 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.0ms) 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.2ms) 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-25 16:24:39.108337"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.108211"], ["updated_at", "2025-11-25 16:24:39.108211"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:24:39.109333"], ["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-25 16:24:39 +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.0ms) 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.0ms) 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] Room data: locked=true, lockType=password, requires=TopSecret123 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=ceo +[BreakEscape] NPC unlock validated: helper_npc can unlock ceo + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) 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-25 16:24:39.123920"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 8ms (Views: 0.1ms | ActiveRecord: 0.3ms (5 queries, 0 cached) | GC: 3.0ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"ceo", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_password_lock:_case_sensitivity +----------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.128452"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.128372"], ["updated_at", "2025-11-25 16:24:39.128372"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"OpenSesame", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: false +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_multiple_unlock_attempts_should_update_state_correctly +------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.130964"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.130869"], ["updated_at", "2025-11-25 16:24:39.130869"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:24:39.132915"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:24:39.134736"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:24:39.136435"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_unlock_non-existent_door_should_fail +------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.137893"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.137833"], ["updated_at", "2025-11-25 16:24:39.137833"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +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.0ms) 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.0ms) 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.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_key_lock:_should_trust_client_validation +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.140485"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.140419"], ["updated_at", "2025-11-25 16:24:39.140419"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"drawer_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:24:39.142345"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlock_with_invalid_method_should_fail +-------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.143669"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.143601"], ["updated_at", "2025-11-25 16:24:39.143601"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: invalid_method +[BreakEscape] SECURITY VIOLATION: No valid unlock method for LOCKED door: office_pin, method=invalid_method +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 2ms (Views: 0.8ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 1.8ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_biometric_lock:_should_trust_client_validation +------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.152313"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.151267"], ["updated_at", "2025-11-25 16:24:39.151267"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +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.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:24:39.160187"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 8ms (Views: 0.1ms | ActiveRecord: 0.3ms (5 queries, 0 cached) | GC: 5.8ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_unlock_response_should_not_expose_'requires'_field_for_exploitable_locks +----------------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.168805"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.167710"], ["updated_at", "2025-11-25 16:24:39.167710"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:24:39.172303"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 2ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.2ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_unlock_response_should_filter_requires_from_contents +-------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.174025"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.173959"], ["updated_at", "2025-11-25 16:24:39.173959"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:24:39.176214"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 2ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) 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.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.178262"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.178190"], ["updated_at", "2025-11-25 16:24:39.178190"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:24:39.178906"], ["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-25 16:24:39 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:24:39.180667"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_doors +------------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.182147"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.182085"], ["updated_at", "2025-11-25 16:24:39.182085"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=false, lockType=, requires= +[BreakEscape] Door is unlocked in scenario data, granting access + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:24:39.183905"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_NPC_can_unlock_door_if_player_has_encountered_them_and_NPC_has_permission +------------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.185170"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.185096"], ["updated_at", "2025-11-25 16:24:39.185096"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:24:39.185858"], ["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-25 16:24:39 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin +[BreakEscape] NPC unlock validated: helper_npc can unlock office_pin + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:24:39.187716"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 2ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_correct_PIN_should_unlock +--------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.189606"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.189506"], ["updated_at", "2025-11-25 16:24:39.189506"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:24:39.191642"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_containers +----------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.193187"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.193117"], ["updated_at", "2025-11-25 16:24:39.193117"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:24:39.194959"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlocked_door:_should_grant_access_without_validation +----------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.196191"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.196123"], ["updated_at", "2025-11-25 16:24:39.196123"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=false, lockType=, requires= +[BreakEscape] Door is unlocked in scenario data, granting access + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:24:39.197859"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_locked_container_cannot_be_bypassed_with_method='unlocked' +-------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.199223"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.199160"], ["updated_at", "2025-11-25 16:24:39.199160"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_for_non-existent_NPC +----------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.201524"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.201461"], ["updated_at", "2025-11-25 16:24:39.201461"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_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\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:24:39.202048"], ["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-25 16:24:39 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=fake_npc, target=office_pin +[BreakEscape] NPC not found: fake_npc +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_incorrect_PIN_should_fail +--------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.203936"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.203874"], ["updated_at", "2025-11-25 16:24:39.203874"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: false +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlock_same_door_twice_should_be_idempotent +------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.206320"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.206233"], ["updated_at", "2025-11-25 16:24:39.206233"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:24:39.207997"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_already-unlocked_container_accepts_method='unlocked' +---------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.210806"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.210744"], ["updated_at", "2025-11-25 16:24:39.210744"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:24:39.211349"], ["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-25 16:24:39 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:24:39.212914"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"npc_safe", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_correct_PIN_should_unlock +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.215476"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.215414"], ["updated_at", "2025-11-25 16:24:39.215414"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:24:39.217086"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlocked_container:_should_grant_access_without_validation +---------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.218404"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.218343"], ["updated_at", "2025-11-25 16:24:39.218343"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:24:39.219972"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_lockpick:_should_trust_client_validation +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.221316"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.221253"], ["updated_at", "2025-11-25 16:24:39.221253"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"box_lockpick", "attempt"=>nil, "method"=>"lockpick", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:24:39.223030"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_NPC_unlock_adds_door_to_unlockedRooms +------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.224236"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.224177"], ["updated_at", "2025-11-25 16:24:39.224177"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:24:39.224815"], ["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-25 16:24:39 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin +[BreakEscape] NPC unlock validated: helper_npc can unlock office_pin + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:24:39.226440"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_RFID_lock:_should_trust_client_validation +-------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.227841"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.227770"], ["updated_at", "2025-11-25 16:24:39.227770"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"door_rfid", "attempt"=>nil, "method"=>"rfid", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:24:39.229536"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_bluetooth_lock:_should_trust_client_validation +------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.230774"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.230695"], ["updated_at", "2025-11-25 16:24:39.230695"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"terminal_bluetooth", "attempt"=>nil, "method"=>"bluetooth", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:24:39.232393"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_container_with_password_lock:_correct_password_should_unlock +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.233535"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.233473"], ["updated_at", "2025-11-25 16:24:39.233473"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"secret123", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:24:39.235156"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_password_lock:_incorrect_password_should_fail +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.236456"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.236394"], ["updated_at", "2025-11-25 16:24:39.236394"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"wrongpassword", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: false +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_password_lock:_correct_password_should_unlock +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.238556"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.238493"], ["updated_at", "2025-11-25 16:24:39.238493"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:24:39.240344"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlock_non-existent_object_should_fail +-------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.241728"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.241653"], ["updated_at", "2025-11-25 16:24:39.241653"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_password_lock:_empty_attempt_should_fail +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.243949"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.243887"], ["updated_at", "2025-11-25 16:24:39.243887"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) 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.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.246180"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.246115"], ["updated_at", "2025-11-25 16:24:39.246115"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:24:39.246762"], ["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-25 16:24:39 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_player_has_not_encountered_NPC +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.249024"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.248963"], ["updated_at", "2025-11-25 16:24:39.248963"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:24:39.249593"], ["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-25 16:24:39 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin +[BreakEscape] Player has not encountered NPC: helper_npc +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_locked_door_cannot_be_bypassed_with_method='unlocked' +--------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.251849"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.251787"], ["updated_at", "2025-11-25 16:24:39.251787"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: unlocked +[BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED door: office_pin +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_incorrect_PIN_should_fail +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.254128"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.254067"], ["updated_at", "2025-11-25 16:24:39.254067"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_key_lock:_should_trust_client_validation +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.256369"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.256305"], ["updated_at", "2025-11-25 16:24:39.256305"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_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\":[],\"inventory\":[{\"id\":\"office_key\",\"type\":\"key\",\"name\":\"Office Key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:24:39.256931"], ["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-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=key, requires=office_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=, is_match=true +[BreakEscape] Key office_key found in inventory: true +[BreakEscape] Key validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_key\"],\"unlockedObjects\":[],\"inventory\":[{\"id\":\"office_key\",\"type\":\"key\",\"name\":\"Office Key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:24:39.258481"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_unlockable_is_not_an_array +-------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:24:39.259870"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.259808"], ["updated_at", "2025-11-25 16:24:39.259808"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:24:39.260427"], ["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-25 16:24:39 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------ +BreakEscape::NPCInkLoadingTest: test_npc-barks_should_import_ASSETS_PATH_from_config +------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.262766"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.262732"], ["updated_at", "2025-11-25 16:24:39.262732"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/systems/npc-barks.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/npc-barks.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/npc-barks.js (1.0ms) +Completed 200 OK in 1ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_404_for_non-existent_game +---------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.266082"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.266049"], ["updated_at", "2025-11-25 16:24:39.266049"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/999999/ink?npc=test-npc" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"test-npc", "id"=>"999999"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 999999], ["LIMIT", 1]] +Completed 404 Not Found in 0ms (ActiveRecord: 0.0ms (1 query, 0 cached) | GC: 0.0ms) + +ActiveRecord::RecordNotFound (Couldn't find BreakEscape::Game with 'id'="999999"): + +activerecord (7.2.3) lib/active_record/core.rb:268:in `find' +/home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/controllers/break_escape/games_controller.rb:323:in `set_game' +activesupport (7.2.3) lib/active_support/callbacks.rb:362:in `block in make_lambda' +activesupport (7.2.3) lib/active_support/callbacks.rb:179:in `block in call' +actionpack (7.2.3) lib/abstract_controller/callbacks.rb:34:in `block (2 levels) in ' +activesupport (7.2.3) lib/active_support/callbacks.rb:180:in `call' +activesupport (7.2.3) lib/active_support/callbacks.rb:560:in `block in invoke_before' +activesupport (7.2.3) lib/active_support/callbacks.rb:560:in `each' +activesupport (7.2.3) lib/active_support/callbacks.rb:560:in `invoke_before' +activesupport (7.2.3) lib/active_support/callbacks.rb:119:in `block in run_callbacks' +actiontext (7.2.3) lib/action_text/rendering.rb:25:in `with_renderer' +actiontext (7.2.3) lib/action_text/engine.rb:71:in `block (4 levels) in ' +activesupport (7.2.3) lib/active_support/callbacks.rb:130:in `instance_exec' +activesupport (7.2.3) lib/active_support/callbacks.rb:130:in `block in run_callbacks' +activesupport (7.2.3) lib/active_support/callbacks.rb:141:in `run_callbacks' +actionpack (7.2.3) lib/abstract_controller/callbacks.rb:260:in `process_action' +actionpack (7.2.3) lib/action_controller/metal/rescue.rb:27:in `process_action' +actionpack (7.2.3) lib/action_controller/metal/instrumentation.rb:77:in `block in process_action' +activesupport (7.2.3) lib/active_support/notifications.rb:210:in `block in instrument' +activesupport (7.2.3) lib/active_support/notifications/instrumenter.rb:58:in `instrument' +activesupport (7.2.3) lib/active_support/notifications.rb:210:in `instrument' +actionpack (7.2.3) lib/action_controller/metal/instrumentation.rb:76:in `process_action' +actionpack (7.2.3) lib/action_controller/metal/params_wrapper.rb:259:in `process_action' +activerecord (7.2.3) lib/active_record/railties/controller_runtime.rb:39:in `process_action' +actionpack (7.2.3) lib/abstract_controller/base.rb:152:in `process' +actionview (7.2.3) lib/action_view/rendering.rb:40:in `process' +actionpack (7.2.3) lib/action_controller/metal.rb:252:in `dispatch' +actionpack (7.2.3) lib/action_controller/metal.rb:335:in `dispatch' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:67:in `dispatch' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:50:in `serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:53:in `block in serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:133:in `block in find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `each' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:34:in `serve' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:896:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/static.rb:27:in `call' +railties (7.2.3) lib/rails/engine.rb:535:in `call' +railties (7.2.3) lib/rails/railtie.rb:226:in `public_send' +railties (7.2.3) lib/rails/railtie.rb:226:in `method_missing' +actionpack (7.2.3) lib/action_dispatch/routing/mapper.rb:33:in `block in ' +actionpack (7.2.3) lib/action_dispatch/routing/mapper.rb:62:in `serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:53:in `block in serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:133:in `block in find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `each' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:34:in `serve' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:896:in `call' +rack (3.2.4) lib/rack/tempfile_reaper.rb:20:in `call' +rack (3.2.4) lib/rack/etag.rb:29:in `call' +rack (3.2.4) lib/rack/conditional_get.rb:31:in `call' +rack (3.2.4) lib/rack/head.rb:15:in `call' +actionpack (7.2.3) lib/action_dispatch/http/permissions_policy.rb:38:in `call' +actionpack (7.2.3) lib/action_dispatch/http/content_security_policy.rb:38:in `call' +rack-session (2.1.1) lib/rack/session/abstract/id.rb:274:in `context' +rack-session (2.1.1) lib/rack/session/abstract/id.rb:268:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/cookies.rb:704:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/callbacks.rb:31:in `block in call' +activesupport (7.2.3) lib/active_support/callbacks.rb:101:in `run_callbacks' +actionpack (7.2.3) lib/action_dispatch/middleware/callbacks.rb:30:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/actionable_exceptions.rb:18:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/debug_exceptions.rb:31:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/show_exceptions.rb:32:in `call' +railties (7.2.3) lib/rails/rack/logger.rb:41:in `call_app' +railties (7.2.3) lib/rails/rack/logger.rb:29:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/remote_ip.rb:96:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/request_id.rb:33:in `call' +rack (3.2.4) lib/rack/method_override.rb:28:in `call' +rack (3.2.4) lib/rack/runtime.rb:24:in `call' +activesupport (7.2.3) lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/executor.rb:16:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/static.rb:27:in `call' +rack (3.2.4) lib/rack/sendfile.rb:131:in `call' +railties (7.2.3) lib/rails/engine.rb:535:in `call' +rack-test (2.2.0) lib/rack/test.rb:360:in `process_request' +rack-test (2.2.0) lib/rack/test.rb:153:in `request' +actionpack (7.2.3) lib/action_dispatch/testing/integration.rb:287:in `process' +actionpack (7.2.3) lib/action_dispatch/testing/integration.rb:19:in `get' +actionpack (7.2.3) lib/action_dispatch/testing/integration.rb:378:in `get' +/home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/test/integration/npc_ink_loading_test.rb:155:in `block in ' +minitest (5.26.2) lib/minitest/test.rb:95:in `block (2 levels) in run' +minitest (5.26.2) lib/minitest/test.rb:191:in `capture_exceptions' +minitest (5.26.2) lib/minitest/test.rb:90:in `block in run' +minitest (5.26.2) lib/minitest.rb:383:in `time_it' +minitest (5.26.2) lib/minitest/test.rb:89:in `run' +activesupport (7.2.3) lib/active_support/executor/test_helper.rb:5:in `block in run' +activesupport (7.2.3) lib/active_support/execution_wrapper.rb:104:in `perform' +activesupport (7.2.3) lib/active_support/executor/test_helper.rb:5:in `run' +minitest (5.26.2) lib/minitest.rb:1224:in `run_one_method' +minitest (5.26.2) lib/minitest.rb:463:in `run_one_method' +minitest (5.26.2) lib/minitest.rb:450:in `block (2 levels) in run' +minitest (5.26.2) lib/minitest.rb:446:in `each' +minitest (5.26.2) lib/minitest.rb:446:in `block in run' +minitest (5.26.2) lib/minitest.rb:488:in `on_signal' +minitest (5.26.2) lib/minitest.rb:475:in `with_info_handler' +minitest (5.26.2) lib/minitest.rb:445:in `run' +railties (7.2.3) lib/rails/test_unit/line_filtering.rb:10:in `run' +minitest (5.26.2) lib/minitest.rb:347:in `block in __run' +minitest (5.26.2) lib/minitest.rb:347:in `map' +minitest (5.26.2) lib/minitest.rb:347:in `__run' +minitest (5.26.2) lib/minitest.rb:302:in `run' +minitest (5.26.2) lib/minitest.rb:86:in `block in autorun' + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_npc-lazy-loader_should_construct_correct_API_endpoint_URL +---------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.405859"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.405802"], ["updated_at", "2025-11-25 16:24:39.405802"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/systems/npc-lazy-loader.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/npc-lazy-loader.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/npc-lazy-loader.js (0.1ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_ink_endpoint_should_work_with_underscored_NPC_IDs +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.408290"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.408249"], ["updated_at", "2025-11-25 16:24:39.408249"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=npc-with-underscores" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"npc-with-underscores", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: npc-with-underscores +[BreakEscape] Available NPCs: security_guard (test_room), test-npc (test_room) +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_phone-chat-minigame_should_use_Rails_API_endpoint_for_story_loading +-------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.410598"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.410566"], ["updated_at", "2025-11-25 16:24:39.410566"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/phone-chat/phone-chat-minigame.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/phone-chat/phone-chat-minigame.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/phone-chat/phone-chat-minigame.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_404_for_NPC_without_story_file +--------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.2ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.413368"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.413334"], ["updated_at", "2025-11-25 16:24:39.413334"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=npc-with-no-file" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"npc-with-no-file", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: npc-with-no-file +[BreakEscape] Available NPCs: security_guard (test_room), test-npc (test_room) +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_bad_request_if_npc_parameter_missing +--------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.415806"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.415772"], ["updated_at", "2025-11-25 16:24:39.415772"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 400 Bad Request in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.2ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_npc-manager_should_load_stories_via_API_endpoint +------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.418073"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.418040"], ["updated_at", "2025-11-25 16:24:39.418040"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/systems/npc-manager.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/npc-manager.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/npc-manager.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.2ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_person-chat-minigame_should_use_Rails_API_endpoint_for_story_loading +--------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.420038"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.420007"], ["updated_at", "2025-11-25 16:24:39.420007"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/person-chat/person-chat-minigame.js?v=10" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"v"=>"10", "path"=>"minigames/person-chat/person-chat-minigame.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/person-chat/person-chat-minigame.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_phone-chat-ui_should_import_ASSETS_PATH_from_config +---------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.421716"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.421678"], ["updated_at", "2025-11-25 16:24:39.421678"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/phone-chat/phone-chat-ui.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/phone-chat/phone-chat-ui.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/phone-chat/phone-chat-ui.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_404_for_non-existent_NPC +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.423540"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.423507"], ["updated_at", "2025-11-25 16:24:39.423507"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=non-existent-npc" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"non-existent-npc", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: non-existent-npc +[BreakEscape] Available NPCs: security_guard (test_room), test-npc (test_room) +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_ink_endpoint_should_return_application/json_content_type +--------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.425994"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.425950"], ["updated_at", "2025-11-25 16:24:39.425950"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=security_guard" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"security_guard", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: security_guard +[BreakEscape] Found NPC: security_guard with storyPath: scenarios/ink/security-guard.json +[BreakEscape] Serving ink from: /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/scenarios/ink/security-guard.json +Completed 200 OK in 1ms (Views: 0.3ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.1ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::NPCInkLoadingTest: test_person-chat-portraits_should_import_ASSETS_PATH_from_config +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.428761"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.428725"], ["updated_at", "2025-11-25 16:24:39.428725"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/person-chat/person-chat-portraits.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/person-chat/person-chat-portraits.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/person-chat/person-chat-portraits.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::GamesControllerTest: test_ink_endpoint_should_return_404_for_non-existent_NPC +------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.430728"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.430664"], ["updated_at", "2025-11-25 16:24:39.430664"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=non-existent" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"non-existent", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: non-existent +[BreakEscape] No NPCs found in scenario data +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_unlock_endpoint_should_accept_correct_pin_code +------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.433003"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.432965"], ["updated_at", "2025-11-25 16:24:39.432965"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"room", "targetId"=>"office", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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=room, id=office, attempt=1234, method=pin +[BreakEscape] Object not found: office +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_inventory_endpoint_should_add_items +-------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.435351"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.435309"], ["updated_at", "2025-11-25 16:24:39.435309"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) 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\":\"reception\",\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{},\"locked\":false,\"objects\":[{\"id\":\"note_1\",\"type\":\"note\",\"name\":\"Test Note\",\"takeable\":true}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"inventory\":[],\"health\":100,\"unlockedObjects\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.435897"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.435870"], ["updated_at", "2025-11-25 16:24:39.435870"]] + TRANSACTION (0.0ms) ROLLBACK TO SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::GamesControllerTest: test_ink_endpoint_should_return_404_for_NPC_without_story_file +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.437306"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.437268"], ["updated_at", "2025-11-25 16:24:39.437268"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=missing-npc" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"missing-npc", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: missing-npc +[BreakEscape] No NPCs found in scenario data +Completed 404 Not Found in 1ms (Views: 0.1ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_unlock_endpoint_should_reject_invalid_attempts +------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.439597"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.439559"], ["updated_at", "2025-11-25 16:24:39.439559"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"room", "targetId"=>"office", "attempt"=>"wrong_code", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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=room, id=office, attempt=wrong_code, method=pin +[BreakEscape] Object not found: office +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_show_should_return_HTML_with_game_container +---------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.441825"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.441787"], ["updated_at", "2025-11-25 16:24:39.441787"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.6ms | GC: 0.1ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.8ms | GC: 0.1ms) +Completed 200 OK in 2ms (Views: 1.2ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_scenario_endpoint_should_return_JSON +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.446268"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.446229"], ["updated_at", "2025-11-25 16:24:39.446229"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#scenario as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------- +BreakEscape::GamesControllerTest: test_should_show_game +------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.448661"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.448623"], ["updated_at", "2025-11-25 16:24:39.448623"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.1ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.2ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.3ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_sync_state_should_update_player_state_for_current_room +--------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.451411"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.451374"], ["updated_at", "2025-11-25 16:24:39.451374"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#sync_state as HTML + Parameters: {"currentRoom"=>"reception", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_ink_endpoint_should_require_npc_parameter +-------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.454077"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.454040"], ["updated_at", "2025-11-25 16:24:39.454040"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 400 Bad Request in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_show_should_inject_game_configuration +---------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.456256"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.456218"], ["updated_at", "2025-11-25 16:24:39.456218"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.2ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.2ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.3ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_JS:_should_serve_core_game_module +------------------------------------------------------------------------------ +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Headers:_should_include_Content-Length +----------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Phaser:_main_JS_imports_GAME_CONFIG +-------------------------------------------------------------------------------- +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_JS:_should_serve_nested_files +-------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Minigame:_should_serve_lockpicking_sounds +-------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_click.mp3" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_click.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_click.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_success.mp3" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_success.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_success.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Assets:_should_return_404_for_non-existent_files +--------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/non-existent.mp3" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/non-existent.mp3"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.2ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Minigame:_should_serve_lockpicking_script +-------------------------------------------------------------------------------------- +Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/lockpicking-game-phaser.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_CSS_files_are_non-empty +------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Assets:_should_serve_PNG_tiles_with_correct_MIME_type +-------------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_JavaScript_files_are_non-empty +-------------------------------------------------------------------------------------- +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Headers:_should_include_Cache-Control +---------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Security:_should_prevent_directory_traversal_in_assets +--------------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/../../config/database.yml" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/database.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_HTML:_should_return_404_for_non-existent_files +------------------------------------------------------------------------------------------- +Started GET "/break_escape/non-existent.html" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 + +ActionController::RoutingError (No route matches [GET] "/break_escape/non-existent.html"): + + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Assets:_should_serve_nested_files +------------------------------------------------------------------------------ +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Routes:_should_handle_files_with_multiple_dots +------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door_sheet_32.png" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_sheet_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_sheet_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Security:_should_prevent_directory_traversal_in_CSS +------------------------------------------------------------------------------------------------ +Started GET "/break_escape/css/../../config/database.yml" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/database.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Headers:_should_set_Content-Disposition_to_inline +---------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_audio_files_are_non-empty +--------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Assets:_should_serve_audio_with_correct_MIME_type +---------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Security:_should_prevent_directory_traversal_in_JS +----------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/../../config/secrets.yml" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/secrets.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_JS:_should_serve_files_with_correct_MIME_type +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Phaser:_game.js_has_asset_references_without_prefix +------------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Routes:_should_capture_complex_paths_with_segments +----------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Phaser:_constants_define_GAME_CONFIG_with_baseURL +---------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_CSS:_should_return_404_for_non-existent_files +------------------------------------------------------------------------------------------ +Started GET "/break_escape/css/non-existent.css" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"non-existent.css"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_CSS:_should_serve_files_with_correct_MIME_type +------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.1ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_HTML:_should_serve_test_files_with_correct_MIME_type +------------------------------------------------------------------------------------------------- +Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as HTML + Parameters: {"filename"=>"test-assets"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/test-assets.html (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_image_files_are_non-empty +--------------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Routes:_should_capture_full_filename_with_extension +------------------------------------------------------------------------------------------------ +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_JS:_should_return_404_for_non-existent_files +----------------------------------------------------------------------------------------- +Started GET "/break_escape/js/non-existent.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"non-existent.js"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_CSS:_should_serve_with_inline_disposition +-------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_all_response_headers_are_correct +------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_baseURL_prevents_duplicate_asset_paths +------------------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_should_load_GAME_CONFIG_with_proper_baseURL +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_sound_manager_module +-------------------------------------------------------------------------------- +Started GET "/break_escape/js/systems/sound-manager.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/sound-manager.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/sound-manager.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_asset_paths_work_without_assets_prefix_in_load_calls +--------------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_door_tile_image +--------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door.png" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_lockpicking_minigame +-------------------------------------------------------------------------------- +Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/lockpicking-game-phaser.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_minigame_starters +----------------------------------------------------------------------------- +Started GET "/break_escape/js/systems/minigame-starters.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/minigame-starters.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/minigame-starters.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_key-operations_minigame_module +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/minigames/lockpicking/key-operations.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/key-operations.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/key-operations.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_test_asset_page_loads_correctly +------------------------------------------------------------------------------ +Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as HTML + Parameters: {"filename"=>"test-assets"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/test-assets.html (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_complete_asset_loading_path_for_lockpicking +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/lockpicking-game-phaser.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_click.mp3" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_click.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_click.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_overtension.mp3" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_overtension.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_overtension.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_reset.mp3" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_reset.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_reset.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_set.mp3" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_set.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_set.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_success.mp3" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_success.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_success.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_tension.mp3" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_tension.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_tension.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_wrong.mp3" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_wrong.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_wrong.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_route_constraints_correctly_capture_file_extensions +-------------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_load_all_required_game_files_in_correct_order +--------------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_game_core_with_asset_references +------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_CSS_files_should_be_accessible_from_main_game +-------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_security:_cannot_access_files_outside_break_escape_directory +----------------------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/../../config/secrets.yml" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/secrets.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/js/../../config/database.yml" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/database.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/../../config/secrets.yml" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/secrets.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------- +BreakEscape::MissionTest: test_scenario_path_returns_correct_path +----------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------- +BreakEscape::MissionTest: test_should_validate_uniqueness_of_name +----------------------------------------------------------------- + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Exists? (0.1ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" = ? LIMIT ? [["name", "test"], ["LIMIT", 1]] + BreakEscape::Mission Create (0.1ms) INSERT INTO "break_escape_missions" ("name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at", "secgen_scenario", "collection") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["name", "test"], ["display_name", "Test"], ["description", nil], ["published", 0], ["difficulty_level", 1], ["created_at", "2025-11-25 16:24:39.540992"], ["updated_at", "2025-11-25 16:24:39.540992"], ["secgen_scenario", nil], ["collection", "default"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" = ? LIMIT ? [["name", "test"], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::MissionTest: test_published_scope_returns_only_published_missions +------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? AND "break_escape_missions"."id" = ? LIMIT ? [["published", 1], ["id", 418560898], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 636030761], ["LIMIT", 1]] + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? AND "break_escape_missions"."id" = ? LIMIT ? [["published", 1], ["id", 636030761], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------- +BreakEscape::MissionTest: test_should_validate_presence_of_name +--------------------------------------------------------------- + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" IS NULL LIMIT ? [["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_GIF_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_JPEG_content_type +----------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_OGG_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_is_case_insensitive +-------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_HTML_content_type +----------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_SVG_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_WOFF2_font_content_type +----------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_handles_multiple_dots_in_filename +---------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_WAV_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_returns_octet-stream_for_unknown_extensions +-------------------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_JSON_content_type +----------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_JavaScript_content_type +----------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_PNG_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_WOFF_font_content_type +---------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_TTF_font_content_type +--------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_CSS_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_MP3_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_get_index +---------------------------------------------------------- +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.0ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" = ? [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.2ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 5.4ms | GC: 0.1ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 5.5ms | GC: 0.1ms) +Completed 200 OK in 6ms (Views: 5.4ms | ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_show_published_mission +----------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] +Started GET "/break_escape/missions/418560898" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::MissionsController#show as HTML + Parameters: {"id"=>"418560898"} + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."player_type" = ? AND "break_escape_games"."player_id" = ? AND "break_escape_games"."mission_id" = ? LIMIT ? [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) 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", "{\"scenario_brief\":\"Hi! You are a cyber investigator tasked with uncovering evidence of corporate espionage. Anonymous tips suggest the CEO has been selling company secrets, but you need proof.\",\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office1\"},\"npcs\":[{\"id\":\"neye_eve\",\"displayName\":\"Neye Eve\",\"storyPath\":\"scenarios/ink/neye-eve.json\",\"avatar\":\"assets/npc/avatars/npc_adversary.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\"},{\"id\":\"gossip_girl\",\"displayName\":\"Gossip Girl\",\"storyPath\":\"scenarios/ink/gossip-girl.json\",\"avatar\":\"assets/npc/avatars/npc_neutral.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"timedMessages\":[{\"delay\":5000,\"message\":\"Hey! 👋 Got any juicy gossip for me today?\",\"type\":\"text\"}]},{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"storyPath\":\"scenarios/ink/helper-npc.json\",\"avatar\":\"assets/npc/avatars/npc_helper.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"unlockable\":[\"secure_vault\",\"ceo\"],\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":15000},{\"eventPattern\":\"door_unlocked\",\"targetKnot\":\"on_door_unlocked\",\"cooldown\":8000},{\"eventPattern\":\"door_unlock_attempt\",\"targetKnot\":\"on_door_attempt\",\"cooldown\":12000},{\"eventPattern\":\"object_interacted\",\"targetKnot\":\"on_ceo_desk_interact\",\"condition\":\"data.objectType === 'desk_ceo'\",\"cooldown\":10000},{\"eventPattern\":\"item_picked_up:*\",\"targetKnot\":\"on_item_found\",\"cooldown\":20000},{\"eventPattern\":\"room_entered\",\"targetKnot\":\"on_room_entered\",\"cooldown\":45000,\"maxTriggers\":3},{\"eventPattern\":\"room_discovered\",\"targetKnot\":\"on_room_discovered\",\"cooldown\":15000,\"maxTriggers\":5},{\"eventPattern\":\"room_entered:ceo\",\"targetKnot\":\"on_ceo_office_entered\",\"onceOnly\":true}]}],\"objects\":[{\"type\":\"phone\",\"name\":\"Reception Phone\",\"takeable\":false,\"readable\":true,\"voice\":\"Hi, this is the IT Team. Security breach detected in server room. Changed access code to 4829.\",\"sender\":\"IT Team\",\"timestamp\":\"2:15 AM\",\"observations\":\"The reception phone's message light is blinking urgently\"},{\"type\":\"notes\",\"name\":\"Security Log\",\"takeable\":true,\"readable\":true,\"text\":\"Unusual after-hours access detected:\\n- CEO office: 11:30 PM\\n- Server room: 2:15 AM\\n- CEO office again: 3:45 AM\",\"observations\":\"A concerning security log from last night\"},{\"type\":\"pc\",\"name\":\"Reception Computer\",\"takeable\":false,\"lockType\":\"password\",\"passwordHint\":\"Optional hint text\",\"showHint\":true,\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"requires\":\"secret123\",\"observations\":\"The reception's computer, currently locked\",\"postitNote\":\"Password: secret123\",\"showPostit\":true,\"contents\":[{\"type\":\"text_file\",\"name\":\"Private\",\"takeable\":false,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\"}]},{\"type\":\"tablet\",\"name\":\"Tablet Device\",\"takeable\":true,\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"A locked tablet device that requires Bluetooth pairing\"},{\"type\":\"bluetooth_scanner\",\"name\":\"Bluetooth Scanner\",\"takeable\":true,\"observations\":\"A device for detecting nearby Bluetooth signals\",\"canScanBluetooth\":true},{\"type\":\"key\",\"name\":\"Office Key\",\"takeable\":true,\"key_id\":\"office1_key\",\"keyPins\":[65,25,65,25],\"observations\":\"A key to access the office areas\"},{\"type\":\"pin-cracker\",\"name\":\"PIN Cracker\",\"takeable\":true,\"observations\":\"A sophisticated device that can analyze PIN entry patterns and provide feedback on attempts\"},{\"type\":\"safe\",\"name\":\"Reception Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9573\",\"observations\":\"A small wall safe behind the reception desk. Looks like it needs a 4-digit code.\",\"contents\":[{\"type\":\"notes\",\"name\":\"IT Access Credentials\",\"takeable\":true,\"readable\":true,\"text\":\"Emergency IT Admin Credentials:\\nUsername: admin\\nPassword: ITsecure2024\\n\\nServer Room Backup Code: 4829\\nCEO Office Alarm Override: 1337\",\"observations\":\"Sensitive IT credentials that could be very useful\"}]}]},\"office1\":{\"type\":\"room_office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office1_key\",\"keyPins\":[65,25,65,25],\"difficulty\":\"easy\",\"door_sign\":\"4A Hot Desks\",\"connections\":{\"north\":[\"office2\",\"office3\"],\"south\":\"reception\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"requires\":\"password\",\"hasFingerprint\":true,\"fingerprintOwner\":\"ceo\",\"fingerprintDifficulty\":\"medium\",\"observations\":\"A computer with a cybersecurity alert on screen. There might be fingerprints on the keyboard.\"},{\"type\":\"notes\",\"name\":\"IT Memo\",\"takeable\":true,\"readable\":true,\"text\":\"URGENT: Multiple unauthorized access attempts detected from CEO's office IP address\",\"observations\":\"A concerning IT department memo\"},{\"type\":\"fingerprint_kit\",\"name\":\"Fingerprint Kit\",\"takeable\":true,\"observations\":\"A kit used for collecting fingerprints from surfaces\"}]},\"office2\":{\"type\":\"room_office\",\"connections\":{\"north\":\"ceo\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"office2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: office2024\",\"showPostit\":true,\"observations\":\"A standard office computer with a sticky note on the monitor\"},{\"type\":\"notes\",\"name\":\"Shredded Document\",\"takeable\":true,\"readable\":true,\"text\":\"Partially readable: '...offshore account...transfer complete...delete all traces...'\",\"observations\":\"A partially shredded document that someone failed to dispose of properly\"},{\"type\":\"key\",\"name\":\"CEO Office Key\",\"takeable\":true,\"key_id\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"observations\":\"A spare key to the CEO's office, carelessly left behind\"}]},\"office3\":{\"type\":\"room_office\",\"connections\":{\"north\":\"server1\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"IT Staff Computer\",\"takeable\":false,\"requires\":\"bluetooth\",\"lockType\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"An IT staff computer showing network security logs\"},{\"type\":\"notes\",\"name\":\"Network Logs\",\"takeable\":true,\"readable\":true,\"text\":\"Large data transfers detected to unknown external IPs - All originating from CEO's office\",\"observations\":\"Suspicious network activity logs\"}]},\"ceo\":{\"type\":\"room_ceo\",\"connections\":{\"north\":\"closet\",\"south\":\"office2\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"difficulty\":\"easy\",\"objects\":[{\"type\":\"pc\",\"name\":\"CEO Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"ceo2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: ceo2024\",\"showPostit\":true,\"observations\":\"The CEO's laptop, still warm - recently used. A sticky note is attached to the screen.\"},{\"type\":\"suitcase\",\"name\":\"CEO Briefcase\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"difficulty\":\"medium\",\"observations\":\"An expensive leather briefcase with a sturdy lock\",\"contents\":[{\"type\":\"notes\",\"name\":\"Private Note\",\"takeable\":true,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\",\"observations\":\"A hastily written note on expensive paper\"},{\"type\":\"key\",\"name\":\"Safe Key\",\"takeable\":true,\"key_id\":\"safe_key\",\"keyPins\":[52,29,44,37],\"observations\":\"A heavy-duty safe key hidden behind server equipment\"}]},{\"type\":\"phone\",\"name\":\"CEO Phone\",\"takeable\":false,\"readable\":true,\"text\":\"Recent calls: 'Offshore Bank', 'Unknown', 'Data Buyer'\",\"sender\":\"Call Log\",\"timestamp\":\"Last 24 hours\",\"observations\":\"The CEO's phone shows suspicious recent calls\"}]},\"closet\":{\"type\":\"room_closet\",\"connections\":{\"south\":\"ceo\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"7391\",\"objects\":[{\"type\":\"safe\",\"name\":\"Hidden Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"safe_key\",\"keyPins\":[52,29,44,37],\"difficulty\":\"hard\",\"observations\":\"A well-hidden wall safe behind a painting\",\"contents\":[{\"type\":\"notes\",\"name\":\"Incriminating Documents\",\"takeable\":true,\"readable\":true,\"text\":\"Contract for sale of proprietary technology\\nBank transfers from competing companies\\nDetails of upcoming corporate espionage operations\",\"observations\":\"A folder containing damning evidence of corporate espionage. Congratulations! You've recovered the incriminating documents. flag{ceo_exfil_flag}\"}]}]},\"server1\":{\"type\":\"room_servers\",\"connections\":{\"south\":\"office3\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"4829\",\"objects\":[{\"type\":\"pc\",\"name\":\"Server Terminal\",\"takeable\":false,\"observations\":\"The main server terminal showing massive data exfiltration\"},{\"type\":\"key\",\"name\":\"Briefcase Key\",\"takeable\":true,\"key_id\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.555268"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.554570"], ["updated_at", "2025-11-25 16:24:39.554570"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Redirected to http://www.example.com/break_escape/games/1 +Completed 302 Found in 2ms (ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------ +BreakEscape::MissionsControllerTest: test_index_should_return_HTML_with_mission_list +------------------------------------------------------------------------------------ +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.0ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" = ? [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 0.6ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.6ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.8ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_create_game_and_redirect_when_showing_mission +---------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Count (0.0ms) SELECT COUNT(*) FROM "break_escape_games" +Started GET "/break_escape/missions/418560898" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::MissionsController#show as HTML + Parameters: {"id"=>"418560898"} + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."player_type" = ? AND "break_escape_games"."player_id" = ? AND "break_escape_games"."mission_id" = ? LIMIT ? [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) 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", "{\"scenario_brief\":\"Hi! You are a cyber investigator tasked with uncovering evidence of corporate espionage. Anonymous tips suggest the CEO has been selling company secrets, but you need proof.\",\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office1\"},\"npcs\":[{\"id\":\"neye_eve\",\"displayName\":\"Neye Eve\",\"storyPath\":\"scenarios/ink/neye-eve.json\",\"avatar\":\"assets/npc/avatars/npc_adversary.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\"},{\"id\":\"gossip_girl\",\"displayName\":\"Gossip Girl\",\"storyPath\":\"scenarios/ink/gossip-girl.json\",\"avatar\":\"assets/npc/avatars/npc_neutral.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"timedMessages\":[{\"delay\":5000,\"message\":\"Hey! 👋 Got any juicy gossip for me today?\",\"type\":\"text\"}]},{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"storyPath\":\"scenarios/ink/helper-npc.json\",\"avatar\":\"assets/npc/avatars/npc_helper.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"unlockable\":[\"secure_vault\",\"ceo\"],\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":15000},{\"eventPattern\":\"door_unlocked\",\"targetKnot\":\"on_door_unlocked\",\"cooldown\":8000},{\"eventPattern\":\"door_unlock_attempt\",\"targetKnot\":\"on_door_attempt\",\"cooldown\":12000},{\"eventPattern\":\"object_interacted\",\"targetKnot\":\"on_ceo_desk_interact\",\"condition\":\"data.objectType === 'desk_ceo'\",\"cooldown\":10000},{\"eventPattern\":\"item_picked_up:*\",\"targetKnot\":\"on_item_found\",\"cooldown\":20000},{\"eventPattern\":\"room_entered\",\"targetKnot\":\"on_room_entered\",\"cooldown\":45000,\"maxTriggers\":3},{\"eventPattern\":\"room_discovered\",\"targetKnot\":\"on_room_discovered\",\"cooldown\":15000,\"maxTriggers\":5},{\"eventPattern\":\"room_entered:ceo\",\"targetKnot\":\"on_ceo_office_entered\",\"onceOnly\":true}]}],\"objects\":[{\"type\":\"phone\",\"name\":\"Reception Phone\",\"takeable\":false,\"readable\":true,\"voice\":\"Hi, this is the IT Team. Security breach detected in server room. Changed access code to 4829.\",\"sender\":\"IT Team\",\"timestamp\":\"2:15 AM\",\"observations\":\"The reception phone's message light is blinking urgently\"},{\"type\":\"notes\",\"name\":\"Security Log\",\"takeable\":true,\"readable\":true,\"text\":\"Unusual after-hours access detected:\\n- CEO office: 11:30 PM\\n- Server room: 2:15 AM\\n- CEO office again: 3:45 AM\",\"observations\":\"A concerning security log from last night\"},{\"type\":\"pc\",\"name\":\"Reception Computer\",\"takeable\":false,\"lockType\":\"password\",\"passwordHint\":\"Optional hint text\",\"showHint\":true,\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"requires\":\"secret123\",\"observations\":\"The reception's computer, currently locked\",\"postitNote\":\"Password: secret123\",\"showPostit\":true,\"contents\":[{\"type\":\"text_file\",\"name\":\"Private\",\"takeable\":false,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\"}]},{\"type\":\"tablet\",\"name\":\"Tablet Device\",\"takeable\":true,\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"A locked tablet device that requires Bluetooth pairing\"},{\"type\":\"bluetooth_scanner\",\"name\":\"Bluetooth Scanner\",\"takeable\":true,\"observations\":\"A device for detecting nearby Bluetooth signals\",\"canScanBluetooth\":true},{\"type\":\"key\",\"name\":\"Office Key\",\"takeable\":true,\"key_id\":\"office1_key\",\"keyPins\":[65,25,65,25],\"observations\":\"A key to access the office areas\"},{\"type\":\"pin-cracker\",\"name\":\"PIN Cracker\",\"takeable\":true,\"observations\":\"A sophisticated device that can analyze PIN entry patterns and provide feedback on attempts\"},{\"type\":\"safe\",\"name\":\"Reception Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9573\",\"observations\":\"A small wall safe behind the reception desk. Looks like it needs a 4-digit code.\",\"contents\":[{\"type\":\"notes\",\"name\":\"IT Access Credentials\",\"takeable\":true,\"readable\":true,\"text\":\"Emergency IT Admin Credentials:\\nUsername: admin\\nPassword: ITsecure2024\\n\\nServer Room Backup Code: 4829\\nCEO Office Alarm Override: 1337\",\"observations\":\"Sensitive IT credentials that could be very useful\"}]}]},\"office1\":{\"type\":\"room_office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office1_key\",\"keyPins\":[65,25,65,25],\"difficulty\":\"easy\",\"door_sign\":\"4A Hot Desks\",\"connections\":{\"north\":[\"office2\",\"office3\"],\"south\":\"reception\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"requires\":\"password\",\"hasFingerprint\":true,\"fingerprintOwner\":\"ceo\",\"fingerprintDifficulty\":\"medium\",\"observations\":\"A computer with a cybersecurity alert on screen. There might be fingerprints on the keyboard.\"},{\"type\":\"notes\",\"name\":\"IT Memo\",\"takeable\":true,\"readable\":true,\"text\":\"URGENT: Multiple unauthorized access attempts detected from CEO's office IP address\",\"observations\":\"A concerning IT department memo\"},{\"type\":\"fingerprint_kit\",\"name\":\"Fingerprint Kit\",\"takeable\":true,\"observations\":\"A kit used for collecting fingerprints from surfaces\"}]},\"office2\":{\"type\":\"room_office\",\"connections\":{\"north\":\"ceo\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"office2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: office2024\",\"showPostit\":true,\"observations\":\"A standard office computer with a sticky note on the monitor\"},{\"type\":\"notes\",\"name\":\"Shredded Document\",\"takeable\":true,\"readable\":true,\"text\":\"Partially readable: '...offshore account...transfer complete...delete all traces...'\",\"observations\":\"A partially shredded document that someone failed to dispose of properly\"},{\"type\":\"key\",\"name\":\"CEO Office Key\",\"takeable\":true,\"key_id\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"observations\":\"A spare key to the CEO's office, carelessly left behind\"}]},\"office3\":{\"type\":\"room_office\",\"connections\":{\"north\":\"server1\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"IT Staff Computer\",\"takeable\":false,\"requires\":\"bluetooth\",\"lockType\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"An IT staff computer showing network security logs\"},{\"type\":\"notes\",\"name\":\"Network Logs\",\"takeable\":true,\"readable\":true,\"text\":\"Large data transfers detected to unknown external IPs - All originating from CEO's office\",\"observations\":\"Suspicious network activity logs\"}]},\"ceo\":{\"type\":\"room_ceo\",\"connections\":{\"north\":\"closet\",\"south\":\"office2\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"difficulty\":\"easy\",\"objects\":[{\"type\":\"pc\",\"name\":\"CEO Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"ceo2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: ceo2024\",\"showPostit\":true,\"observations\":\"The CEO's laptop, still warm - recently used. A sticky note is attached to the screen.\"},{\"type\":\"suitcase\",\"name\":\"CEO Briefcase\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"difficulty\":\"medium\",\"observations\":\"An expensive leather briefcase with a sturdy lock\",\"contents\":[{\"type\":\"notes\",\"name\":\"Private Note\",\"takeable\":true,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\",\"observations\":\"A hastily written note on expensive paper\"},{\"type\":\"key\",\"name\":\"Safe Key\",\"takeable\":true,\"key_id\":\"safe_key\",\"keyPins\":[52,29,44,37],\"observations\":\"A heavy-duty safe key hidden behind server equipment\"}]},{\"type\":\"phone\",\"name\":\"CEO Phone\",\"takeable\":false,\"readable\":true,\"text\":\"Recent calls: 'Offshore Bank', 'Unknown', 'Data Buyer'\",\"sender\":\"Call Log\",\"timestamp\":\"Last 24 hours\",\"observations\":\"The CEO's phone shows suspicious recent calls\"}]},\"closet\":{\"type\":\"room_closet\",\"connections\":{\"south\":\"ceo\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"7391\",\"objects\":[{\"type\":\"safe\",\"name\":\"Hidden Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"safe_key\",\"keyPins\":[52,29,44,37],\"difficulty\":\"hard\",\"observations\":\"A well-hidden wall safe behind a painting\",\"contents\":[{\"type\":\"notes\",\"name\":\"Incriminating Documents\",\"takeable\":true,\"readable\":true,\"text\":\"Contract for sale of proprietary technology\\nBank transfers from competing companies\\nDetails of upcoming corporate espionage operations\",\"observations\":\"A folder containing damning evidence of corporate espionage. Congratulations! You've recovered the incriminating documents. flag{ceo_exfil_flag}\"}]}]},\"server1\":{\"type\":\"room_servers\",\"connections\":{\"south\":\"office3\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"4829\",\"objects\":[{\"type\":\"pc\",\"name\":\"Server Terminal\",\"takeable\":false,\"observations\":\"The main server terminal showing massive data exfiltration\"},{\"type\":\"key\",\"name\":\"Briefcase Key\",\"takeable\":true,\"key_id\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.560842"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.560208"], ["updated_at", "2025-11-25 16:24:39.560208"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Redirected to http://www.example.com/break_escape/games/1 +Completed 302 Found in 2ms (ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Count (0.0ms) SELECT COUNT(*) FROM "break_escape_games" + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_index_should_display_published_missions +--------------------------------------------------------------------------------- +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.0ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" = ? [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 0.5ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.6ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.6ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::RoomLazyLoadTest: test_should_return_400_when_room_id_is_missing +----------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.564759"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.564723"], ["updated_at", "2025-11-25 16:24:39.564723"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::RoomLazyLoadTest: test_should_return_room_data_for_valid_room_id +----------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.565782"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.565750"], ["updated_at", "2025-11-25 16:24:39.565750"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/room/test_room" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#room as HTML + Parameters: {"id"=>"1", "room_id"=>"test_room"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Serving room data for: test_room +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------ +BreakEscape::RoomLazyLoadTest: test_room_response_includes_all_room_data +------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.567807"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.567776"], ["updated_at", "2025-11-25 16:24:39.567776"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/room/test_room" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#room as HTML + Parameters: {"id"=>"1", "room_id"=>"test_room"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Serving room data for: test_room +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::RoomLazyLoadTest: test_should_return_404_for_non-existent_room +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.569741"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.569707"], ["updated_at", "2025-11-25 16:24:39.569707"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/room/non_existent_room" for 127.0.0.1 at 2025-11-25 16:24:39 +0000 +Processing by BreakEscape::GamesController#room as HTML + Parameters: {"id"=>"1", "room_id"=>"non_existent_room"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_removes_objects_and_npcs +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.571673"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.571633"], ["updated_at", "2025-11-25 16:24:39.571633"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_removes_room_contents +--------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.572784"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.572744"], ["updated_at", "2025-11-25 16:24:39.572744"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_preserves_lock_requirements +--------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.573784"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.573744"], ["updated_at", "2025-11-25 16:24:39.573744"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------------ +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_preserves_navigation_structure +------------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.574761"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.574723"], ["updated_at", "2025-11-25 16:24:39.574723"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_does_not_modify_original +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.575742"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.575690"], ["updated_at", "2025-11-25 16:24:39.575690"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GameTest: test_has_lockpick_in_inventory_should_find_lockpicks +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.576836"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.576807"], ["updated_at", "2025-11-25 16:24:39.576807"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=lockpick, scenarioData.type=, is_lockpick=true +[BreakEscape] Lockpick found in inventory: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------- +BreakEscape::GameTest: test_key_takes_precedence_over_lockpick_attempt +---------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.577833"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.577805"], ["updated_at", "2025-11-25 16:24:39.577805"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=key +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office1_key in inventory (2 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=true +[BreakEscape] Key office1_key found in inventory: true +[BreakEscape] Key validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------- +BreakEscape::GameTest: test_should_clamp_health_between_0_and_100 +----------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.578849"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.578821"], ["updated_at", "2025-11-25 16:24:39.578821"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":0}"], ["updated_at", "2025-11-25 16:24:39.579386"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------- +BreakEscape::GameTest: test_should_validate_unlock_with_correct_key +------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.580252"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.580225"], ["updated_at", "2025-11-25 16:24:39.580225"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=key +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office1_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=true +[BreakEscape] Key office1_key found in inventory: true +[BreakEscape] Key validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------- +BreakEscape::GameTest: test_has_lockpick_in_inventory_should_not_find_non-lockpick_items +---------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.581244"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.581217"], ["updated_at", "2025-11-25 16:24:39.581217"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=key, scenarioData.type=, is_lockpick=false +[BreakEscape] Lockpick found in inventory: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------- +BreakEscape::GameTest: test_should_reject_lockpick_unlock_without_lockpick_in_inventory +--------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.582179"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.582152"], ["updated_at", "2025-11-25 16:24:39.582152"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=lockpick +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: lockpick +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=key, scenarioData.type=, is_lockpick=false +[BreakEscape] Lockpick found in inventory: false +[BreakEscape] Lockpick validation result: false +[BreakEscape] validate_unlock returning: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------- +BreakEscape::GameTest: test_should_unlock_room +---------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.583155"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.583128"], ["updated_at", "2025-11-25 16:24:39.583128"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\",\"office\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:24:39.583567"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------ +BreakEscape::GameTest: test_should_update_health +------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.584403"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.584376"], ["updated_at", "2025-11-25 16:24:39.584376"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":50}"], ["updated_at", "2025-11-25 16:24:39.584819"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------- +BreakEscape::GameTest: test_should_track_inventory +-------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.585640"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.585614"], ["updated_at", "2025-11-25 16:24:39.585614"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"key\",\"name\":\"Test Key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:24:39.586055"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------- +BreakEscape::GameTest: test_should_validate_unlock_with_lockpick +---------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.586889"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.586862"], ["updated_at", "2025-11-25 16:24:39.586862"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=lockpick +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: lockpick +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=lockpick, scenarioData.type=, is_lockpick=true +[BreakEscape] Lockpick found in inventory: true +[BreakEscape] Lockpick validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------ +BreakEscape::GameTest: test_lockpick_should_bypass_key_requirement +------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.587824"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.587797"], ["updated_at", "2025-11-25 16:24:39.587797"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=secure_vault, attempt=, method=lockpick +[BreakEscape] Room data: locked=true, lockType=key, requires=vault_master_key +[BreakEscape] Room is LOCKED, method must be valid: lockpick +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=lockpick, scenarioData.type=, is_lockpick=true +[BreakEscape] Lockpick found in inventory: true +[BreakEscape] Lockpick validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::GameTest: test_should_allow_access_to_unlocked_doors_regardless_of_method +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.588897"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.588869"], ["updated_at", "2025-11-25 16:24:39.588869"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=reception, attempt=, method=unlocked +[BreakEscape] Door already unlocked in player state, granting access + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::GameTest: test_should_reject_locked_door_without_any_unlock_method +------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.589915"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.589886"], ["updated_at", "2025-11-25 16:24:39.589886"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method= +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: +[BreakEscape] SECURITY VIOLATION: No valid unlock method for LOCKED door: office1, method= +[BreakEscape] validate_unlock returning: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------- +BreakEscape::GameTest: test_should_reject_unlock_without_required_key +--------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.590915"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.590887"], ["updated_at", "2025-11-25 16:24:39.590887"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=key +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office1_key in inventory (1 items) +[BreakEscape] Inventory item: name=Wrong Key, key_id=wrong_key, is_match=false +[BreakEscape] Key office1_key found in inventory: false +[BreakEscape] Key validation result: false +[BreakEscape] validate_unlock returning: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GameTest: test_has_key_in_inventory_should_find_keys_by_key_id +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.591903"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.591876"], ["updated_at", "2025-11-25 16:24:39.591876"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Checking for key office1_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=true +[BreakEscape] Key office1_key found in inventory: true +[BreakEscape] Checking for key wrong_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=false +[BreakEscape] Key wrong_key found in inventory: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------- +BreakEscape::GameTest: test_should_belong_to_player_and_mission +--------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:39.592872"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:39.592846"], ["updated_at", "2025-11-25 16:24:39.592846"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------- +BreakEscapeTest: test_it_has_a_version_number +--------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + ActiveRecord::InternalMetadata Load (0.1ms) 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.0ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC + TRANSACTION (0.0ms) begin transaction +  (0.1ms) PRAGMA foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys = ON +  (0.0ms) PRAGMA foreign_keys = OFF + Fixtures Load (0.1ms) 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-25 16:24:49', '2025-11-25 16:24:49'); +INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-25 16:24:49', '2025-11-25 16:24:49'); +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-25 16:24:49', '2025-11-25 16:24:49'); +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-25 16:24:49', '2025-11-25 16:24:49') +  (0.0ms) PRAGMA defer_foreign_keys = 0 +  (0.0ms) PRAGMA foreign_keys = 1 + TRANSACTION (0.8ms) commit transaction +  (0.0ms) PRAGMA foreign_key_check + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_inventory_endpoint_should_add_items +-------------------------------------------------------------------------- + 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.2ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:49.038676"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:49.038577"], ["updated_at", "2025-11-25 16:24:49.038577"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) 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\":\"reception\",\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{},\"locked\":false,\"objects\":[{\"id\":\"note_1\",\"type\":\"note\",\"name\":\"Test Note\",\"takeable\":true}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"inventory\":[],\"health\":100,\"unlockedObjects\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[]}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:24:49.039533"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:24:49.039506"], ["updated_at", "2025-11-25 16:24:49.039506"]] + TRANSACTION (0.0ms) ROLLBACK TO SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + ActiveRecord::InternalMetadata Load (0.1ms) 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.0ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC + TRANSACTION (0.0ms) begin transaction +  (0.1ms) PRAGMA foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys = ON +  (0.0ms) PRAGMA foreign_keys = OFF + Fixtures Load (0.1ms) 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-25 16:25:14', '2025-11-25 16:25:14'); +INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-25 16:25:14', '2025-11-25 16:25:14'); +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-25 16:25:14', '2025-11-25 16:25:14'); +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-25 16:25:14', '2025-11-25 16:25:14') +  (0.0ms) PRAGMA defer_foreign_keys = 0 +  (0.0ms) PRAGMA foreign_keys = 1 + TRANSACTION (1.5ms) commit transaction +  (0.0ms) PRAGMA foreign_key_check + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_asset_paths_work_without_assets_prefix_in_load_calls +--------------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (1.0ms) +Completed 200 OK in 2ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_minigame_starters +----------------------------------------------------------------------------- +Started GET "/break_escape/js/systems/minigame-starters.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/minigame-starters.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/minigame-starters.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_all_response_headers_are_correct +------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_complete_asset_loading_path_for_lockpicking +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/lockpicking-game-phaser.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_click.mp3" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_click.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_click.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_overtension.mp3" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_overtension.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_overtension.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_reset.mp3" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_reset.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_reset.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_set.mp3" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_set.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_set.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_success.mp3" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_success.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_success.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_tension.mp3" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_tension.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_tension.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_wrong.mp3" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_wrong.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_wrong.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_load_all_required_game_files_in_correct_order +--------------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_game_core_with_asset_references +------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_CSS_files_should_be_accessible_from_main_game +-------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_key-operations_minigame_module +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/minigames/lockpicking/key-operations.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/key-operations.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/key-operations.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_baseURL_prevents_duplicate_asset_paths +------------------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_security:_cannot_access_files_outside_break_escape_directory +----------------------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/../../config/secrets.yml" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/secrets.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 1ms (Views: 1.4ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/js/../../config/database.yml" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/database.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/../../config/secrets.yml" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/secrets.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_lockpicking_minigame +-------------------------------------------------------------------------------- +Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/lockpicking-game-phaser.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_route_constraints_correctly_capture_file_extensions +-------------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_sound_manager_module +-------------------------------------------------------------------------------- +Started GET "/break_escape/js/systems/sound-manager.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/sound-manager.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/sound-manager.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_test_asset_page_loads_correctly +------------------------------------------------------------------------------ +Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as HTML + Parameters: {"filename"=>"test-assets"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/test-assets.html (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_should_load_GAME_CONFIG_with_proper_baseURL +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_door_tile_image +--------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door.png" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_HTML_content_type +----------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_PNG_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_GIF_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_JSON_content_type +----------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_TTF_font_content_type +--------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_returns_octet-stream_for_unknown_extensions +-------------------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_handles_multiple_dots_in_filename +---------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_CSS_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_WOFF2_font_content_type +----------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_JPEG_content_type +----------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_MP3_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_is_case_insensitive +-------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_WOFF_font_content_type +---------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_WAV_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_JavaScript_content_type +----------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_OGG_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_SVG_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_does_not_modify_original +------------------------------------------------------------------------------------------------ + 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.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.282786"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.282692"], ["updated_at", "2025-11-25 16:25:14.282692"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------------ +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_preserves_navigation_structure +------------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.284279"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.284235"], ["updated_at", "2025-11-25 16:25:14.284235"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_removes_room_contents +--------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.285446"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.285405"], ["updated_at", "2025-11-25 16:25:14.285405"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_removes_objects_and_npcs +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.286447"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.286408"], ["updated_at", "2025-11-25 16:25:14.286408"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_preserves_lock_requirements +--------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.287459"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.287421"], ["updated_at", "2025-11-25 16:25:14.287421"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_index_should_display_published_missions +--------------------------------------------------------------------------------- +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.0ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" = ? [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.2ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 5.6ms | GC: 0.1ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 5.7ms | GC: 0.1ms) +Completed 200 OK in 8ms (Views: 5.8ms | ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 0.2ms) + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_create_game_and_redirect_when_showing_mission +---------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Count (0.0ms) SELECT COUNT(*) FROM "break_escape_games" +Started GET "/break_escape/missions/418560898" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::MissionsController#show as HTML + Parameters: {"id"=>"418560898"} + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."player_type" = ? AND "break_escape_games"."player_id" = ? AND "break_escape_games"."mission_id" = ? LIMIT ? [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) 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", "{\"scenario_brief\":\"Hi! You are a cyber investigator tasked with uncovering evidence of corporate espionage. Anonymous tips suggest the CEO has been selling company secrets, but you need proof.\",\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office1\"},\"npcs\":[{\"id\":\"neye_eve\",\"displayName\":\"Neye Eve\",\"storyPath\":\"scenarios/ink/neye-eve.json\",\"avatar\":\"assets/npc/avatars/npc_adversary.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\"},{\"id\":\"gossip_girl\",\"displayName\":\"Gossip Girl\",\"storyPath\":\"scenarios/ink/gossip-girl.json\",\"avatar\":\"assets/npc/avatars/npc_neutral.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"timedMessages\":[{\"delay\":5000,\"message\":\"Hey! 👋 Got any juicy gossip for me today?\",\"type\":\"text\"}]},{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"storyPath\":\"scenarios/ink/helper-npc.json\",\"avatar\":\"assets/npc/avatars/npc_helper.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"unlockable\":[\"secure_vault\",\"ceo\"],\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":15000},{\"eventPattern\":\"door_unlocked\",\"targetKnot\":\"on_door_unlocked\",\"cooldown\":8000},{\"eventPattern\":\"door_unlock_attempt\",\"targetKnot\":\"on_door_attempt\",\"cooldown\":12000},{\"eventPattern\":\"object_interacted\",\"targetKnot\":\"on_ceo_desk_interact\",\"condition\":\"data.objectType === 'desk_ceo'\",\"cooldown\":10000},{\"eventPattern\":\"item_picked_up:*\",\"targetKnot\":\"on_item_found\",\"cooldown\":20000},{\"eventPattern\":\"room_entered\",\"targetKnot\":\"on_room_entered\",\"cooldown\":45000,\"maxTriggers\":3},{\"eventPattern\":\"room_discovered\",\"targetKnot\":\"on_room_discovered\",\"cooldown\":15000,\"maxTriggers\":5},{\"eventPattern\":\"room_entered:ceo\",\"targetKnot\":\"on_ceo_office_entered\",\"onceOnly\":true}]}],\"objects\":[{\"type\":\"phone\",\"name\":\"Reception Phone\",\"takeable\":false,\"readable\":true,\"voice\":\"Hi, this is the IT Team. Security breach detected in server room. Changed access code to 4829.\",\"sender\":\"IT Team\",\"timestamp\":\"2:15 AM\",\"observations\":\"The reception phone's message light is blinking urgently\"},{\"type\":\"notes\",\"name\":\"Security Log\",\"takeable\":true,\"readable\":true,\"text\":\"Unusual after-hours access detected:\\n- CEO office: 11:30 PM\\n- Server room: 2:15 AM\\n- CEO office again: 3:45 AM\",\"observations\":\"A concerning security log from last night\"},{\"type\":\"pc\",\"name\":\"Reception Computer\",\"takeable\":false,\"lockType\":\"password\",\"passwordHint\":\"Optional hint text\",\"showHint\":true,\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"requires\":\"secret123\",\"observations\":\"The reception's computer, currently locked\",\"postitNote\":\"Password: secret123\",\"showPostit\":true,\"contents\":[{\"type\":\"text_file\",\"name\":\"Private\",\"takeable\":false,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\"}]},{\"type\":\"tablet\",\"name\":\"Tablet Device\",\"takeable\":true,\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"A locked tablet device that requires Bluetooth pairing\"},{\"type\":\"bluetooth_scanner\",\"name\":\"Bluetooth Scanner\",\"takeable\":true,\"observations\":\"A device for detecting nearby Bluetooth signals\",\"canScanBluetooth\":true},{\"type\":\"key\",\"name\":\"Office Key\",\"takeable\":true,\"key_id\":\"office1_key\",\"keyPins\":[65,25,65,25],\"observations\":\"A key to access the office areas\"},{\"type\":\"pin-cracker\",\"name\":\"PIN Cracker\",\"takeable\":true,\"observations\":\"A sophisticated device that can analyze PIN entry patterns and provide feedback on attempts\"},{\"type\":\"safe\",\"name\":\"Reception Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9573\",\"observations\":\"A small wall safe behind the reception desk. Looks like it needs a 4-digit code.\",\"contents\":[{\"type\":\"notes\",\"name\":\"IT Access Credentials\",\"takeable\":true,\"readable\":true,\"text\":\"Emergency IT Admin Credentials:\\nUsername: admin\\nPassword: ITsecure2024\\n\\nServer Room Backup Code: 4829\\nCEO Office Alarm Override: 1337\",\"observations\":\"Sensitive IT credentials that could be very useful\"}]}]},\"office1\":{\"type\":\"room_office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office1_key\",\"keyPins\":[65,25,65,25],\"difficulty\":\"easy\",\"door_sign\":\"4A Hot Desks\",\"connections\":{\"north\":[\"office2\",\"office3\"],\"south\":\"reception\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"requires\":\"password\",\"hasFingerprint\":true,\"fingerprintOwner\":\"ceo\",\"fingerprintDifficulty\":\"medium\",\"observations\":\"A computer with a cybersecurity alert on screen. There might be fingerprints on the keyboard.\"},{\"type\":\"notes\",\"name\":\"IT Memo\",\"takeable\":true,\"readable\":true,\"text\":\"URGENT: Multiple unauthorized access attempts detected from CEO's office IP address\",\"observations\":\"A concerning IT department memo\"},{\"type\":\"fingerprint_kit\",\"name\":\"Fingerprint Kit\",\"takeable\":true,\"observations\":\"A kit used for collecting fingerprints from surfaces\"}]},\"office2\":{\"type\":\"room_office\",\"connections\":{\"north\":\"ceo\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"office2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: office2024\",\"showPostit\":true,\"observations\":\"A standard office computer with a sticky note on the monitor\"},{\"type\":\"notes\",\"name\":\"Shredded Document\",\"takeable\":true,\"readable\":true,\"text\":\"Partially readable: '...offshore account...transfer complete...delete all traces...'\",\"observations\":\"A partially shredded document that someone failed to dispose of properly\"},{\"type\":\"key\",\"name\":\"CEO Office Key\",\"takeable\":true,\"key_id\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"observations\":\"A spare key to the CEO's office, carelessly left behind\"}]},\"office3\":{\"type\":\"room_office\",\"connections\":{\"north\":\"server1\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"IT Staff Computer\",\"takeable\":false,\"requires\":\"bluetooth\",\"lockType\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"An IT staff computer showing network security logs\"},{\"type\":\"notes\",\"name\":\"Network Logs\",\"takeable\":true,\"readable\":true,\"text\":\"Large data transfers detected to unknown external IPs - All originating from CEO's office\",\"observations\":\"Suspicious network activity logs\"}]},\"ceo\":{\"type\":\"room_ceo\",\"connections\":{\"north\":\"closet\",\"south\":\"office2\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"difficulty\":\"easy\",\"objects\":[{\"type\":\"pc\",\"name\":\"CEO Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"ceo2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: ceo2024\",\"showPostit\":true,\"observations\":\"The CEO's laptop, still warm - recently used. A sticky note is attached to the screen.\"},{\"type\":\"suitcase\",\"name\":\"CEO Briefcase\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"difficulty\":\"medium\",\"observations\":\"An expensive leather briefcase with a sturdy lock\",\"contents\":[{\"type\":\"notes\",\"name\":\"Private Note\",\"takeable\":true,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\",\"observations\":\"A hastily written note on expensive paper\"},{\"type\":\"key\",\"name\":\"Safe Key\",\"takeable\":true,\"key_id\":\"safe_key\",\"keyPins\":[52,29,44,37],\"observations\":\"A heavy-duty safe key hidden behind server equipment\"}]},{\"type\":\"phone\",\"name\":\"CEO Phone\",\"takeable\":false,\"readable\":true,\"text\":\"Recent calls: 'Offshore Bank', 'Unknown', 'Data Buyer'\",\"sender\":\"Call Log\",\"timestamp\":\"Last 24 hours\",\"observations\":\"The CEO's phone shows suspicious recent calls\"}]},\"closet\":{\"type\":\"room_closet\",\"connections\":{\"south\":\"ceo\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"7391\",\"objects\":[{\"type\":\"safe\",\"name\":\"Hidden Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"safe_key\",\"keyPins\":[52,29,44,37],\"difficulty\":\"hard\",\"observations\":\"A well-hidden wall safe behind a painting\",\"contents\":[{\"type\":\"notes\",\"name\":\"Incriminating Documents\",\"takeable\":true,\"readable\":true,\"text\":\"Contract for sale of proprietary technology\\nBank transfers from competing companies\\nDetails of upcoming corporate espionage operations\",\"observations\":\"A folder containing damning evidence of corporate espionage. Congratulations! You've recovered the incriminating documents. flag{ceo_exfil_flag}\"}]}]},\"server1\":{\"type\":\"room_servers\",\"connections\":{\"south\":\"office3\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"4829\",\"objects\":[{\"type\":\"pc\",\"name\":\"Server Terminal\",\"takeable\":false,\"observations\":\"The main server terminal showing massive data exfiltration\"},{\"type\":\"key\",\"name\":\"Briefcase Key\",\"takeable\":true,\"key_id\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.300317"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.299687"], ["updated_at", "2025-11-25 16:25:14.299687"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Redirected to http://www.example.com/break_escape/games/1 +Completed 302 Found in 2ms (ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Count (0.0ms) SELECT COUNT(*) FROM "break_escape_games" + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_show_published_mission +----------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] +Started GET "/break_escape/missions/418560898" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::MissionsController#show as HTML + Parameters: {"id"=>"418560898"} + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."player_type" = ? AND "break_escape_games"."player_id" = ? AND "break_escape_games"."mission_id" = ? LIMIT ? [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) 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", "{\"scenario_brief\":\"Hi! You are a cyber investigator tasked with uncovering evidence of corporate espionage. Anonymous tips suggest the CEO has been selling company secrets, but you need proof.\",\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office1\"},\"npcs\":[{\"id\":\"neye_eve\",\"displayName\":\"Neye Eve\",\"storyPath\":\"scenarios/ink/neye-eve.json\",\"avatar\":\"assets/npc/avatars/npc_adversary.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\"},{\"id\":\"gossip_girl\",\"displayName\":\"Gossip Girl\",\"storyPath\":\"scenarios/ink/gossip-girl.json\",\"avatar\":\"assets/npc/avatars/npc_neutral.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"timedMessages\":[{\"delay\":5000,\"message\":\"Hey! 👋 Got any juicy gossip for me today?\",\"type\":\"text\"}]},{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"storyPath\":\"scenarios/ink/helper-npc.json\",\"avatar\":\"assets/npc/avatars/npc_helper.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"unlockable\":[\"secure_vault\",\"ceo\"],\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":15000},{\"eventPattern\":\"door_unlocked\",\"targetKnot\":\"on_door_unlocked\",\"cooldown\":8000},{\"eventPattern\":\"door_unlock_attempt\",\"targetKnot\":\"on_door_attempt\",\"cooldown\":12000},{\"eventPattern\":\"object_interacted\",\"targetKnot\":\"on_ceo_desk_interact\",\"condition\":\"data.objectType === 'desk_ceo'\",\"cooldown\":10000},{\"eventPattern\":\"item_picked_up:*\",\"targetKnot\":\"on_item_found\",\"cooldown\":20000},{\"eventPattern\":\"room_entered\",\"targetKnot\":\"on_room_entered\",\"cooldown\":45000,\"maxTriggers\":3},{\"eventPattern\":\"room_discovered\",\"targetKnot\":\"on_room_discovered\",\"cooldown\":15000,\"maxTriggers\":5},{\"eventPattern\":\"room_entered:ceo\",\"targetKnot\":\"on_ceo_office_entered\",\"onceOnly\":true}]}],\"objects\":[{\"type\":\"phone\",\"name\":\"Reception Phone\",\"takeable\":false,\"readable\":true,\"voice\":\"Hi, this is the IT Team. Security breach detected in server room. Changed access code to 4829.\",\"sender\":\"IT Team\",\"timestamp\":\"2:15 AM\",\"observations\":\"The reception phone's message light is blinking urgently\"},{\"type\":\"notes\",\"name\":\"Security Log\",\"takeable\":true,\"readable\":true,\"text\":\"Unusual after-hours access detected:\\n- CEO office: 11:30 PM\\n- Server room: 2:15 AM\\n- CEO office again: 3:45 AM\",\"observations\":\"A concerning security log from last night\"},{\"type\":\"pc\",\"name\":\"Reception Computer\",\"takeable\":false,\"lockType\":\"password\",\"passwordHint\":\"Optional hint text\",\"showHint\":true,\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"requires\":\"secret123\",\"observations\":\"The reception's computer, currently locked\",\"postitNote\":\"Password: secret123\",\"showPostit\":true,\"contents\":[{\"type\":\"text_file\",\"name\":\"Private\",\"takeable\":false,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\"}]},{\"type\":\"tablet\",\"name\":\"Tablet Device\",\"takeable\":true,\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"A locked tablet device that requires Bluetooth pairing\"},{\"type\":\"bluetooth_scanner\",\"name\":\"Bluetooth Scanner\",\"takeable\":true,\"observations\":\"A device for detecting nearby Bluetooth signals\",\"canScanBluetooth\":true},{\"type\":\"key\",\"name\":\"Office Key\",\"takeable\":true,\"key_id\":\"office1_key\",\"keyPins\":[65,25,65,25],\"observations\":\"A key to access the office areas\"},{\"type\":\"pin-cracker\",\"name\":\"PIN Cracker\",\"takeable\":true,\"observations\":\"A sophisticated device that can analyze PIN entry patterns and provide feedback on attempts\"},{\"type\":\"safe\",\"name\":\"Reception Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9573\",\"observations\":\"A small wall safe behind the reception desk. Looks like it needs a 4-digit code.\",\"contents\":[{\"type\":\"notes\",\"name\":\"IT Access Credentials\",\"takeable\":true,\"readable\":true,\"text\":\"Emergency IT Admin Credentials:\\nUsername: admin\\nPassword: ITsecure2024\\n\\nServer Room Backup Code: 4829\\nCEO Office Alarm Override: 1337\",\"observations\":\"Sensitive IT credentials that could be very useful\"}]}]},\"office1\":{\"type\":\"room_office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office1_key\",\"keyPins\":[65,25,65,25],\"difficulty\":\"easy\",\"door_sign\":\"4A Hot Desks\",\"connections\":{\"north\":[\"office2\",\"office3\"],\"south\":\"reception\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"requires\":\"password\",\"hasFingerprint\":true,\"fingerprintOwner\":\"ceo\",\"fingerprintDifficulty\":\"medium\",\"observations\":\"A computer with a cybersecurity alert on screen. There might be fingerprints on the keyboard.\"},{\"type\":\"notes\",\"name\":\"IT Memo\",\"takeable\":true,\"readable\":true,\"text\":\"URGENT: Multiple unauthorized access attempts detected from CEO's office IP address\",\"observations\":\"A concerning IT department memo\"},{\"type\":\"fingerprint_kit\",\"name\":\"Fingerprint Kit\",\"takeable\":true,\"observations\":\"A kit used for collecting fingerprints from surfaces\"}]},\"office2\":{\"type\":\"room_office\",\"connections\":{\"north\":\"ceo\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"office2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: office2024\",\"showPostit\":true,\"observations\":\"A standard office computer with a sticky note on the monitor\"},{\"type\":\"notes\",\"name\":\"Shredded Document\",\"takeable\":true,\"readable\":true,\"text\":\"Partially readable: '...offshore account...transfer complete...delete all traces...'\",\"observations\":\"A partially shredded document that someone failed to dispose of properly\"},{\"type\":\"key\",\"name\":\"CEO Office Key\",\"takeable\":true,\"key_id\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"observations\":\"A spare key to the CEO's office, carelessly left behind\"}]},\"office3\":{\"type\":\"room_office\",\"connections\":{\"north\":\"server1\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"IT Staff Computer\",\"takeable\":false,\"requires\":\"bluetooth\",\"lockType\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"An IT staff computer showing network security logs\"},{\"type\":\"notes\",\"name\":\"Network Logs\",\"takeable\":true,\"readable\":true,\"text\":\"Large data transfers detected to unknown external IPs - All originating from CEO's office\",\"observations\":\"Suspicious network activity logs\"}]},\"ceo\":{\"type\":\"room_ceo\",\"connections\":{\"north\":\"closet\",\"south\":\"office2\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"difficulty\":\"easy\",\"objects\":[{\"type\":\"pc\",\"name\":\"CEO Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"ceo2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: ceo2024\",\"showPostit\":true,\"observations\":\"The CEO's laptop, still warm - recently used. A sticky note is attached to the screen.\"},{\"type\":\"suitcase\",\"name\":\"CEO Briefcase\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"difficulty\":\"medium\",\"observations\":\"An expensive leather briefcase with a sturdy lock\",\"contents\":[{\"type\":\"notes\",\"name\":\"Private Note\",\"takeable\":true,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\",\"observations\":\"A hastily written note on expensive paper\"},{\"type\":\"key\",\"name\":\"Safe Key\",\"takeable\":true,\"key_id\":\"safe_key\",\"keyPins\":[52,29,44,37],\"observations\":\"A heavy-duty safe key hidden behind server equipment\"}]},{\"type\":\"phone\",\"name\":\"CEO Phone\",\"takeable\":false,\"readable\":true,\"text\":\"Recent calls: 'Offshore Bank', 'Unknown', 'Data Buyer'\",\"sender\":\"Call Log\",\"timestamp\":\"Last 24 hours\",\"observations\":\"The CEO's phone shows suspicious recent calls\"}]},\"closet\":{\"type\":\"room_closet\",\"connections\":{\"south\":\"ceo\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"7391\",\"objects\":[{\"type\":\"safe\",\"name\":\"Hidden Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"safe_key\",\"keyPins\":[52,29,44,37],\"difficulty\":\"hard\",\"observations\":\"A well-hidden wall safe behind a painting\",\"contents\":[{\"type\":\"notes\",\"name\":\"Incriminating Documents\",\"takeable\":true,\"readable\":true,\"text\":\"Contract for sale of proprietary technology\\nBank transfers from competing companies\\nDetails of upcoming corporate espionage operations\",\"observations\":\"A folder containing damning evidence of corporate espionage. Congratulations! You've recovered the incriminating documents. flag{ceo_exfil_flag}\"}]}]},\"server1\":{\"type\":\"room_servers\",\"connections\":{\"south\":\"office3\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"4829\",\"objects\":[{\"type\":\"pc\",\"name\":\"Server Terminal\",\"takeable\":false,\"observations\":\"The main server terminal showing massive data exfiltration\"},{\"type\":\"key\",\"name\":\"Briefcase Key\",\"takeable\":true,\"key_id\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.303474"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.302891"], ["updated_at", "2025-11-25 16:25:14.302891"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Redirected to http://www.example.com/break_escape/games/1 +Completed 302 Found in 2ms (ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_get_index +---------------------------------------------------------- +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.0ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" = ? [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 0.5ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.6ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.6ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------ +BreakEscape::MissionsControllerTest: test_index_should_return_HTML_with_mission_list +------------------------------------------------------------------------------------ +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.0ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" = ? [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.5ms | GC: 0.4ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 2.1ms | GC: 1.5ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 2.1ms | GC: 1.5ms) +Completed 200 OK in 3ms (Views: 2.3ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 1.6ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_phone-chat-ui_should_import_ASSETS_PATH_from_config +---------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.312715"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.312653"], ["updated_at", "2025-11-25 16:25:14.312653"]] + TRANSACTION (0.6ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/phone-chat/phone-chat-ui.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/phone-chat/phone-chat-ui.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/phone-chat/phone-chat-ui.js (0.1ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.3ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_npc-manager_should_load_stories_via_API_endpoint +------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.5ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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 (1.2ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.320392"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.320350"], ["updated_at", "2025-11-25 16:25:14.320350"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/systems/npc-manager.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/npc-manager.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/npc-manager.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (1.0ms) begin transaction +------------------------------------------------------------------------------------ +BreakEscape::NPCInkLoadingTest: test_npc-barks_should_import_ASSETS_PATH_from_config +------------------------------------------------------------------------------------ + 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.0ms) 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 (1.0ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.331630"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.331554"], ["updated_at", "2025-11-25 16:25:14.331554"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/systems/npc-barks.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/npc-barks.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/npc-barks.js (0.7ms) +Completed 200 OK in 1ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.7ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_ink_endpoint_should_work_with_underscored_NPC_IDs +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.340249"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.340214"], ["updated_at", "2025-11-25 16:25:14.340214"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=npc-with-underscores" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"npc-with-underscores", "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.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: npc-with-underscores +[BreakEscape] Available NPCs: security_guard (test_room), test-npc (test_room) +Completed 404 Not Found in 2ms (Views: 0.1ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_ink_endpoint_should_return_application/json_content_type +--------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.346894"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.346854"], ["updated_at", "2025-11-25 16:25:14.346854"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=security_guard" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"security_guard", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: security_guard +[BreakEscape] Found NPC: security_guard with storyPath: scenarios/ink/security-guard.json +[BreakEscape] Serving ink from: /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/scenarios/ink/security-guard.json +Completed 200 OK in 1ms (Views: 0.4ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::NPCInkLoadingTest: test_person-chat-portraits_should_import_ASSETS_PATH_from_config +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.349788"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.349754"], ["updated_at", "2025-11-25 16:25:14.349754"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/person-chat/person-chat-portraits.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/person-chat/person-chat-portraits.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/person-chat/person-chat-portraits.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_404_for_non-existent_NPC +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.351484"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.351452"], ["updated_at", "2025-11-25 16:25:14.351452"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=non-existent-npc" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"non-existent-npc", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: non-existent-npc +[BreakEscape] Available NPCs: security_guard (test_room), test-npc (test_room) +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_npc-lazy-loader_should_construct_correct_API_endpoint_URL +---------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.353561"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.353525"], ["updated_at", "2025-11-25 16:25:14.353525"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/systems/npc-lazy-loader.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/npc-lazy-loader.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/npc-lazy-loader.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_person-chat-minigame_should_use_Rails_API_endpoint_for_story_loading +--------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.355218"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.355182"], ["updated_at", "2025-11-25 16:25:14.355182"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/person-chat/person-chat-minigame.js?v=10" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"v"=>"10", "path"=>"minigames/person-chat/person-chat-minigame.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/person-chat/person-chat-minigame.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_404_for_non-existent_game +---------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.356909"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.356876"], ["updated_at", "2025-11-25 16:25:14.356876"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/999999/ink?npc=test-npc" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"test-npc", "id"=>"999999"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 999999], ["LIMIT", 1]] +Completed 404 Not Found in 0ms (ActiveRecord: 0.0ms (1 query, 0 cached) | GC: 0.0ms) + +ActiveRecord::RecordNotFound (Couldn't find BreakEscape::Game with 'id'="999999"): + +activerecord (7.2.3) lib/active_record/core.rb:268:in `find' +/home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/controllers/break_escape/games_controller.rb:323:in `set_game' +activesupport (7.2.3) lib/active_support/callbacks.rb:362:in `block in make_lambda' +activesupport (7.2.3) lib/active_support/callbacks.rb:179:in `block in call' +actionpack (7.2.3) lib/abstract_controller/callbacks.rb:34:in `block (2 levels) in ' +activesupport (7.2.3) lib/active_support/callbacks.rb:180:in `call' +activesupport (7.2.3) lib/active_support/callbacks.rb:560:in `block in invoke_before' +activesupport (7.2.3) lib/active_support/callbacks.rb:560:in `each' +activesupport (7.2.3) lib/active_support/callbacks.rb:560:in `invoke_before' +activesupport (7.2.3) lib/active_support/callbacks.rb:119:in `block in run_callbacks' +actiontext (7.2.3) lib/action_text/rendering.rb:25:in `with_renderer' +actiontext (7.2.3) lib/action_text/engine.rb:71:in `block (4 levels) in ' +activesupport (7.2.3) lib/active_support/callbacks.rb:130:in `instance_exec' +activesupport (7.2.3) lib/active_support/callbacks.rb:130:in `block in run_callbacks' +activesupport (7.2.3) lib/active_support/callbacks.rb:141:in `run_callbacks' +actionpack (7.2.3) lib/abstract_controller/callbacks.rb:260:in `process_action' +actionpack (7.2.3) lib/action_controller/metal/rescue.rb:27:in `process_action' +actionpack (7.2.3) lib/action_controller/metal/instrumentation.rb:77:in `block in process_action' +activesupport (7.2.3) lib/active_support/notifications.rb:210:in `block in instrument' +activesupport (7.2.3) lib/active_support/notifications/instrumenter.rb:58:in `instrument' +activesupport (7.2.3) lib/active_support/notifications.rb:210:in `instrument' +actionpack (7.2.3) lib/action_controller/metal/instrumentation.rb:76:in `process_action' +actionpack (7.2.3) lib/action_controller/metal/params_wrapper.rb:259:in `process_action' +activerecord (7.2.3) lib/active_record/railties/controller_runtime.rb:39:in `process_action' +actionpack (7.2.3) lib/abstract_controller/base.rb:152:in `process' +actionview (7.2.3) lib/action_view/rendering.rb:40:in `process' +actionpack (7.2.3) lib/action_controller/metal.rb:252:in `dispatch' +actionpack (7.2.3) lib/action_controller/metal.rb:335:in `dispatch' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:67:in `dispatch' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:50:in `serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:53:in `block in serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:133:in `block in find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `each' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:34:in `serve' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:896:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/static.rb:27:in `call' +railties (7.2.3) lib/rails/engine.rb:535:in `call' +railties (7.2.3) lib/rails/railtie.rb:226:in `public_send' +railties (7.2.3) lib/rails/railtie.rb:226:in `method_missing' +actionpack (7.2.3) lib/action_dispatch/routing/mapper.rb:33:in `block in ' +actionpack (7.2.3) lib/action_dispatch/routing/mapper.rb:62:in `serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:53:in `block in serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:133:in `block in find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `each' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:34:in `serve' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:896:in `call' +rack (3.2.4) lib/rack/tempfile_reaper.rb:20:in `call' +rack (3.2.4) lib/rack/etag.rb:29:in `call' +rack (3.2.4) lib/rack/conditional_get.rb:31:in `call' +rack (3.2.4) lib/rack/head.rb:15:in `call' +actionpack (7.2.3) lib/action_dispatch/http/permissions_policy.rb:38:in `call' +actionpack (7.2.3) lib/action_dispatch/http/content_security_policy.rb:38:in `call' +rack-session (2.1.1) lib/rack/session/abstract/id.rb:274:in `context' +rack-session (2.1.1) lib/rack/session/abstract/id.rb:268:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/cookies.rb:704:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/callbacks.rb:31:in `block in call' +activesupport (7.2.3) lib/active_support/callbacks.rb:101:in `run_callbacks' +actionpack (7.2.3) lib/action_dispatch/middleware/callbacks.rb:30:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/actionable_exceptions.rb:18:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/debug_exceptions.rb:31:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/show_exceptions.rb:32:in `call' +railties (7.2.3) lib/rails/rack/logger.rb:41:in `call_app' +railties (7.2.3) lib/rails/rack/logger.rb:29:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/remote_ip.rb:96:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/request_id.rb:33:in `call' +rack (3.2.4) lib/rack/method_override.rb:28:in `call' +rack (3.2.4) lib/rack/runtime.rb:24:in `call' +activesupport (7.2.3) lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/executor.rb:16:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/static.rb:27:in `call' +rack (3.2.4) lib/rack/sendfile.rb:131:in `call' +railties (7.2.3) lib/rails/engine.rb:535:in `call' +rack-test (2.2.0) lib/rack/test.rb:360:in `process_request' +rack-test (2.2.0) lib/rack/test.rb:153:in `request' +actionpack (7.2.3) lib/action_dispatch/testing/integration.rb:287:in `process' +actionpack (7.2.3) lib/action_dispatch/testing/integration.rb:19:in `get' +actionpack (7.2.3) lib/action_dispatch/testing/integration.rb:378:in `get' +/home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/test/integration/npc_ink_loading_test.rb:155:in `block in ' +minitest (5.26.2) lib/minitest/test.rb:95:in `block (2 levels) in run' +minitest (5.26.2) lib/minitest/test.rb:191:in `capture_exceptions' +minitest (5.26.2) lib/minitest/test.rb:90:in `block in run' +minitest (5.26.2) lib/minitest.rb:383:in `time_it' +minitest (5.26.2) lib/minitest/test.rb:89:in `run' +activesupport (7.2.3) lib/active_support/executor/test_helper.rb:5:in `block in run' +activesupport (7.2.3) lib/active_support/execution_wrapper.rb:104:in `perform' +activesupport (7.2.3) lib/active_support/executor/test_helper.rb:5:in `run' +minitest (5.26.2) lib/minitest.rb:1224:in `run_one_method' +minitest (5.26.2) lib/minitest.rb:463:in `run_one_method' +minitest (5.26.2) lib/minitest.rb:450:in `block (2 levels) in run' +minitest (5.26.2) lib/minitest.rb:446:in `each' +minitest (5.26.2) lib/minitest.rb:446:in `block in run' +minitest (5.26.2) lib/minitest.rb:488:in `on_signal' +minitest (5.26.2) lib/minitest.rb:475:in `with_info_handler' +minitest (5.26.2) lib/minitest.rb:445:in `run' +railties (7.2.3) lib/rails/test_unit/line_filtering.rb:10:in `run' +minitest (5.26.2) lib/minitest.rb:347:in `block in __run' +minitest (5.26.2) lib/minitest.rb:347:in `map' +minitest (5.26.2) lib/minitest.rb:347:in `__run' +minitest (5.26.2) lib/minitest.rb:302:in `run' +minitest (5.26.2) lib/minitest.rb:86:in `block in autorun' + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_bad_request_if_npc_parameter_missing +--------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.490616"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.490567"], ["updated_at", "2025-11-25 16:25:14.490567"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 400 Bad Request in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_phone-chat-minigame_should_use_Rails_API_endpoint_for_story_loading +-------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.493113"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.493075"], ["updated_at", "2025-11-25 16:25:14.493075"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/phone-chat/phone-chat-minigame.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/phone-chat/phone-chat-minigame.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/phone-chat/phone-chat-minigame.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_404_for_NPC_without_story_file +--------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.494850"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.494814"], ["updated_at", "2025-11-25 16:25:14.494814"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=npc-with-no-file" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"npc-with-no-file", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: npc-with-no-file +[BreakEscape] Available NPCs: security_guard (test_room), test-npc (test_room) +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------ +BreakEscape::RoomLazyLoadTest: test_room_response_includes_all_room_data +------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.497121"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.497087"], ["updated_at", "2025-11-25 16:25:14.497087"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/room/test_room" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#room as HTML + Parameters: {"id"=>"1", "room_id"=>"test_room"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Serving room data for: test_room +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::RoomLazyLoadTest: test_should_return_404_for_non-existent_room +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.499175"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.499144"], ["updated_at", "2025-11-25 16:25:14.499144"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/room/non_existent_room" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#room as HTML + Parameters: {"id"=>"1", "room_id"=>"non_existent_room"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::RoomLazyLoadTest: test_should_return_room_data_for_valid_room_id +----------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.501072"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.501041"], ["updated_at", "2025-11-25 16:25:14.501041"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/room/test_room" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#room as HTML + Parameters: {"id"=>"1", "room_id"=>"test_room"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Serving room data for: test_room +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::RoomLazyLoadTest: test_should_return_400_when_room_id_is_missing +----------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.502969"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.502939"], ["updated_at", "2025-11-25 16:25:14.502939"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_correct_PIN_should_unlock +--------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.504137"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.504072"], ["updated_at", "2025-11-25 16:25:14.504072"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:14.507779"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_multiple_unlock_attempts_should_update_state_correctly +------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.509271"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.509205"], ["updated_at", "2025-11-25 16:25:14.509205"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:14.510930"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:14.512684"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:14.514414"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_key_lock:_should_trust_client_validation +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.515885"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.515799"], ["updated_at", "2025-11-25 16:25:14.515799"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_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\":[],\"inventory\":[{\"id\":\"office_key\",\"type\":\"key\",\"name\":\"Office Key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:25:14.516425"], ["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-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=key, requires=office_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=, is_match=true +[BreakEscape] Key office_key found in inventory: true +[BreakEscape] Key validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_key\"],\"unlockedObjects\":[],\"inventory\":[{\"id\":\"office_key\",\"type\":\"key\",\"name\":\"Office Key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:25:14.517922"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_doors +------------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.519297"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.519235"], ["updated_at", "2025-11-25 16:25:14.519235"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=false, lockType=, requires= +[BreakEscape] Door is unlocked in scenario data, granting access + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:14.520882"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_key_lock:_should_trust_client_validation +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.522071"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.521987"], ["updated_at", "2025-11-25 16:25:14.521987"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"drawer_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:14.523687"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_unlock_response_should_not_expose_'requires'_field_for_exploitable_locks +----------------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.524857"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.524794"], ["updated_at", "2025-11-25 16:25:14.524794"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:14.526509"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_locked_container_cannot_be_bypassed_with_method='unlocked' +-------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.527700"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.527638"], ["updated_at", "2025-11-25 16:25:14.527638"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) 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.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.530069"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.530006"], ["updated_at", "2025-11-25 16:25:14.530006"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:25:14.530621"], ["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-25 16:25:14 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:14.532211"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_unlock_response_should_filter_requires_from_contents +-------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.533576"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.533514"], ["updated_at", "2025-11-25 16:25:14.533514"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:14.535159"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_NPC_unlock_adds_door_to_unlockedRooms +------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.536316"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.536252"], ["updated_at", "2025-11-25 16:25:14.536252"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:25:14.536863"], ["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-25 16:25:14 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin +[BreakEscape] NPC unlock validated: helper_npc can unlock office_pin + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:14.538405"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_locked_door_cannot_be_bypassed_with_method='unlocked' +--------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.539870"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.539802"], ["updated_at", "2025-11-25 16:25:14.539802"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: unlocked +[BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED door: office_pin +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_incorrect_PIN_should_fail +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.542294"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.542225"], ["updated_at", "2025-11-25 16:25:14.542225"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) 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.0ms) 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.1ms) 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-25 16:25:14.545876"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.545802"], ["updated_at", "2025-11-25 16:25:14.545802"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:25:14.546446"], ["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-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"ceo", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=password, requires=TopSecret123 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=ceo +[BreakEscape] NPC unlock validated: helper_npc can unlock ceo + TRANSACTION (0.0ms) 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.0ms) 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-25 16:25:14.548561"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.4ms (5 queries, 0 cached) | GC: 0.2ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"ceo", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlocked_door:_should_grant_access_without_validation +----------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.2ms) 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-25 16:25:14.551318"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.551257"], ["updated_at", "2025-11-25 16:25:14.551257"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=false, lockType=, requires= +[BreakEscape] Door is unlocked in scenario data, granting access + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) 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-25 16:25:14.553078"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_password_lock:_correct_password_should_unlock +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.554582"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.554521"], ["updated_at", "2025-11-25 16:25:14.554521"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:14.556315"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + 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.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_correct_PIN_should_unlock +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.557739"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.557675"], ["updated_at", "2025-11-25 16:25:14.557675"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:14.559397"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) 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.0ms) 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.1ms) 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-25 16:25:14.560826"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.560766"], ["updated_at", "2025-11-25 16:25:14.560766"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:25:14.561335"], ["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-25 16:25:14 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_RFID_lock:_should_trust_client_validation +-------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.563809"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.563745"], ["updated_at", "2025-11-25 16:25:14.563745"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"door_rfid", "attempt"=>nil, "method"=>"rfid", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:14.565590"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_player_has_not_encountered_NPC +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.566795"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.566737"], ["updated_at", "2025-11-25 16:25:14.566737"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:25:14.567411"], ["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-25 16:25:14 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin +[BreakEscape] Player has not encountered NPC: helper_npc +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_containers +----------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.569852"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.569792"], ["updated_at", "2025-11-25 16:25:14.569792"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:14.571589"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_bluetooth_lock:_should_trust_client_validation +------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.572740"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.572675"], ["updated_at", "2025-11-25 16:25:14.572675"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"terminal_bluetooth", "attempt"=>nil, "method"=>"bluetooth", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:14.574392"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_lockpick:_should_trust_client_validation +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.575632"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.575571"], ["updated_at", "2025-11-25 16:25:14.575571"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"box_lockpick", "attempt"=>nil, "method"=>"lockpick", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:14.577240"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_NPC_can_unlock_door_if_player_has_encountered_them_and_NPC_has_permission +------------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.578499"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.578438"], ["updated_at", "2025-11-25 16:25:14.578438"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:25:14.579021"], ["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-25 16:25:14 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin +[BreakEscape] NPC unlock validated: helper_npc can unlock office_pin + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:14.580742"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) 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_password_lock:_case_sensitivity +----------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.582247"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.582184"], ["updated_at", "2025-11-25 16:25:14.582184"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"OpenSesame", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: false +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.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.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.584497"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.584433"], ["updated_at", "2025-11-25 16:25:14.584433"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"scanner_biometric", "attempt"=>nil, "method"=>"biometric", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:14.586311"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.3ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_unlockable_is_not_an_array +-------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.587522"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.587463"], ["updated_at", "2025-11-25 16:25:14.587463"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:25:14.588112"], ["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-25 16:25:14 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlock_with_invalid_method_should_fail +-------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.590235"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.590166"], ["updated_at", "2025-11-25 16:25:14.590166"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: invalid_method +[BreakEscape] SECURITY VIOLATION: No valid unlock method for LOCKED door: office_pin, method=invalid_method +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlocked_container:_should_grant_access_without_validation +---------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.592391"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.592319"], ["updated_at", "2025-11-25 16:25:14.592319"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.1ms) 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-25 16:25:14.593980"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_already-unlocked_container_accepts_method='unlocked' +---------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.595439"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.595377"], ["updated_at", "2025-11-25 16:25:14.595377"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:25:14.595970"], ["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-25 16:25:14 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:14.597595"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"npc_safe", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_for_non-existent_NPC +----------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.600196"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.600134"], ["updated_at", "2025-11-25 16:25:14.600134"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_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\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:25:14.600695"], ["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-25 16:25:14 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=fake_npc, target=office_pin +[BreakEscape] NPC not found: fake_npc +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlock_same_door_twice_should_be_idempotent +------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.602799"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.602734"], ["updated_at", "2025-11-25 16:25:14.602734"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:14.604511"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_password_lock:_incorrect_password_should_fail +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.607305"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.607243"], ["updated_at", "2025-11-25 16:25:14.607243"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"wrongpassword", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: false +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlock_non-existent_object_should_fail +-------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.609481"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.609418"], ["updated_at", "2025-11-25 16:25:14.609418"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_password_lock:_empty_attempt_should_fail +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.611661"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.611599"], ["updated_at", "2025-11-25 16:25:14.611599"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_container_with_password_lock:_correct_password_should_unlock +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.613945"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.613881"], ["updated_at", "2025-11-25 16:25:14.613881"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"secret123", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:14.615597"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_unlock_non-existent_door_should_fail +------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.617024"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.616954"], ["updated_at", "2025-11-25 16:25:14.616954"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_incorrect_PIN_should_fail +--------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:14.619364"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.619302"], ["updated_at", "2025-11-25 16:25:14.619302"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: false +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------- +BreakEscapeTest: test_it_has_a_version_number +--------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::MissionTest: test_published_scope_returns_only_published_missions +------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? AND "break_escape_missions"."id" = ? LIMIT ? [["published", 1], ["id", 418560898], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 636030761], ["LIMIT", 1]] + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? AND "break_escape_missions"."id" = ? LIMIT ? [["published", 1], ["id", 636030761], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------- +BreakEscape::MissionTest: test_should_validate_presence_of_name +--------------------------------------------------------------- + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" IS NULL LIMIT ? [["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------- +BreakEscape::MissionTest: test_should_validate_uniqueness_of_name +----------------------------------------------------------------- + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Exists? (0.1ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" = ? LIMIT ? [["name", "test"], ["LIMIT", 1]] + BreakEscape::Mission Create (0.0ms) INSERT INTO "break_escape_missions" ("name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at", "secgen_scenario", "collection") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["name", "test"], ["display_name", "Test"], ["description", nil], ["published", 0], ["difficulty_level", 1], ["created_at", "2025-11-25 16:25:14.623156"], ["updated_at", "2025-11-25 16:25:14.623156"], ["secgen_scenario", nil], ["collection", "default"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" = ? LIMIT ? [["name", "test"], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------- +BreakEscape::MissionTest: test_scenario_path_returns_correct_path +----------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------- +BreakEscape::GameTest: test_has_lockpick_in_inventory_should_not_find_non-lockpick_items +---------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.624631"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.624602"], ["updated_at", "2025-11-25 16:25:14.624602"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=key, scenarioData.type=, is_lockpick=false +[BreakEscape] Lockpick found in inventory: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------ +BreakEscape::GameTest: test_should_update_health +------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.625625"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.625598"], ["updated_at", "2025-11-25 16:25:14.625598"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":50}"], ["updated_at", "2025-11-25 16:25:14.626058"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GameTest: test_has_lockpick_in_inventory_should_find_lockpicks +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.626955"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.626928"], ["updated_at", "2025-11-25 16:25:14.626928"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=lockpick, scenarioData.type=, is_lockpick=true +[BreakEscape] Lockpick found in inventory: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------ +BreakEscape::GameTest: test_lockpick_should_bypass_key_requirement +------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.627924"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.627895"], ["updated_at", "2025-11-25 16:25:14.627895"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=secure_vault, attempt=, method=lockpick +[BreakEscape] Room data: locked=true, lockType=key, requires=vault_master_key +[BreakEscape] Room is LOCKED, method must be valid: lockpick +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=lockpick, scenarioData.type=, is_lockpick=true +[BreakEscape] Lockpick found in inventory: true +[BreakEscape] Lockpick validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::GameTest: test_should_reject_locked_door_without_any_unlock_method +------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.628907"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.628879"], ["updated_at", "2025-11-25 16:25:14.628879"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method= +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: +[BreakEscape] SECURITY VIOLATION: No valid unlock method for LOCKED door: office1, method= +[BreakEscape] validate_unlock returning: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------- +BreakEscape::GameTest: test_should_reject_unlock_without_required_key +--------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.629891"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.629860"], ["updated_at", "2025-11-25 16:25:14.629860"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=key +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office1_key in inventory (1 items) +[BreakEscape] Inventory item: name=Wrong Key, key_id=wrong_key, is_match=false +[BreakEscape] Key office1_key found in inventory: false +[BreakEscape] Key validation result: false +[BreakEscape] validate_unlock returning: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GameTest: test_has_key_in_inventory_should_find_keys_by_key_id +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.630878"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.630851"], ["updated_at", "2025-11-25 16:25:14.630851"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Checking for key office1_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=true +[BreakEscape] Key office1_key found in inventory: true +[BreakEscape] Checking for key wrong_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=false +[BreakEscape] Key wrong_key found in inventory: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------- +BreakEscape::GameTest: test_should_track_inventory +-------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.631847"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.631819"], ["updated_at", "2025-11-25 16:25:14.631819"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"key\",\"name\":\"Test Key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:25:14.632266"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------- +BreakEscape::GameTest: test_key_takes_precedence_over_lockpick_attempt +---------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.633118"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.633089"], ["updated_at", "2025-11-25 16:25:14.633089"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=key +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office1_key in inventory (2 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=true +[BreakEscape] Key office1_key found in inventory: true +[BreakEscape] Key validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------- +BreakEscape::GameTest: test_should_belong_to_player_and_mission +--------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.634080"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.634054"], ["updated_at", "2025-11-25 16:25:14.634054"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------- +BreakEscape::GameTest: test_should_unlock_room +---------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.635016"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.634987"], ["updated_at", "2025-11-25 16:25:14.634987"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\",\"office\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:25:14.635435"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::GameTest: test_should_allow_access_to_unlocked_doors_regardless_of_method +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.636331"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.636300"], ["updated_at", "2025-11-25 16:25:14.636300"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=reception, attempt=, method=unlocked +[BreakEscape] Door already unlocked in player state, granting access + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------- +BreakEscape::GameTest: test_should_validate_unlock_with_correct_key +------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.637329"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.637299"], ["updated_at", "2025-11-25 16:25:14.637299"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=key +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office1_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=true +[BreakEscape] Key office1_key found in inventory: true +[BreakEscape] Key validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------- +BreakEscape::GameTest: test_should_validate_unlock_with_lockpick +---------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.638308"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.638280"], ["updated_at", "2025-11-25 16:25:14.638280"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=lockpick +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: lockpick +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=lockpick, scenarioData.type=, is_lockpick=true +[BreakEscape] Lockpick found in inventory: true +[BreakEscape] Lockpick validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------- +BreakEscape::GameTest: test_should_clamp_health_between_0_and_100 +----------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.639302"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.639273"], ["updated_at", "2025-11-25 16:25:14.639273"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":0}"], ["updated_at", "2025-11-25 16:25:14.639852"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------- +BreakEscape::GameTest: test_should_reject_lockpick_unlock_without_lockpick_in_inventory +--------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.640726"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.640697"], ["updated_at", "2025-11-25 16:25:14.640697"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=lockpick +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: lockpick +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=key, scenarioData.type=, is_lockpick=false +[BreakEscape] Lockpick found in inventory: false +[BreakEscape] Lockpick validation result: false +[BreakEscape] validate_unlock returning: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_ink_endpoint_should_require_npc_parameter +-------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.641918"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.641878"], ["updated_at", "2025-11-25 16:25:14.641878"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 400 Bad Request in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::GamesControllerTest: test_ink_endpoint_should_return_404_for_NPC_without_story_file +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.644279"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.644239"], ["updated_at", "2025-11-25 16:25:14.644239"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=missing-npc" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"missing-npc", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: missing-npc +[BreakEscape] No NPCs found in scenario data +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::GamesControllerTest: test_ink_endpoint_should_return_404_for_non-existent_NPC +------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.647597"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.647559"], ["updated_at", "2025-11-25 16:25:14.647559"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=non-existent" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"non-existent", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: non-existent +[BreakEscape] No NPCs found in scenario data +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_scenario_endpoint_should_return_JSON +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.650230"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.650188"], ["updated_at", "2025-11-25 16:25:14.650188"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#scenario as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_show_should_inject_game_configuration +---------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.652679"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.652642"], ["updated_at", "2025-11-25 16:25:14.652642"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.5ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.5ms | GC: 0.0ms) +Completed 200 OK in 2ms (Views: 0.7ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.1ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_inventory_endpoint_should_add_items +-------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.656321"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.656279"], ["updated_at", "2025-11-25 16:25:14.656279"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[{\"id\":\"note_1\",\"type\":\"note\",\"name\":\"Test Note\",\"takeable\":true}]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:25:14.656794"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/inventory" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#inventory as HTML + Parameters: {"action_type"=>"add", "item"=>{"type"=>"note", "name"=>"Test Note", "id"=>"note_1"}, "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.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] inventory endpoint: action=add, item=#"note", "name"=>"Test Note", "id"=>"note_1"} permitted: false> +[BreakEscape] validate_item_collectible: type=note, id=note_1, name=Test Note +[BreakEscape] Item collection valid: note +[BreakEscape] Adding item to inventory: note / Test Note + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"note\",\"name\":\"Test Note\",\"id\":\"note_1\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:25:14.658675"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Item added successfully. Current inventory: [{"type"=>"note", "name"=>"Test Note", "id"=>"note_1"}] +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------- +BreakEscape::GamesControllerTest: test_should_show_game +------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.660137"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.660097"], ["updated_at", "2025-11-25 16:25:14.660097"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.2ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.2ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.3ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_sync_state_should_update_player_state_for_current_room +--------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.662971"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.662928"], ["updated_at", "2025-11-25 16:25:14.662928"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#sync_state as HTML + Parameters: {"currentRoom"=>"reception", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_unlock_endpoint_should_reject_invalid_attempts +------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.665834"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.665795"], ["updated_at", "2025-11-25 16:25:14.665795"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"room", "targetId"=>"office", "attempt"=>"wrong_code", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) [34mSELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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=room, id=office, attempt=wrong_code, method=pin +[BreakEscape] Object not found: office +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_show_should_return_HTML_with_game_container +---------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.668098"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.668061"], ["updated_at", "2025-11-25 16:25:14.668061"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.1ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.2ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.3ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_unlock_endpoint_should_accept_correct_pin_code +------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:14.671396"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:14.671353"], ["updated_at", "2025-11-25 16:25:14.671353"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"room", "targetId"=>"office", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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=room, id=office, attempt=1234, method=pin +[BreakEscape] Object not found: office +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Routes:_should_capture_full_filename_with_extension +------------------------------------------------------------------------------------------------ +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_JS:_should_serve_files_with_correct_MIME_type +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_HTML:_should_serve_test_files_with_correct_MIME_type +------------------------------------------------------------------------------------------------- +Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as HTML + Parameters: {"filename"=>"test-assets"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/test-assets.html (0.1ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Headers:_should_include_Content-Length +----------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Routes:_should_handle_files_with_multiple_dots +------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door_sheet_32.png" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_sheet_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_sheet_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_audio_files_are_non-empty +--------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_JS:_should_return_404_for_non-existent_files +----------------------------------------------------------------------------------------- +Started GET "/break_escape/js/non-existent.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"non-existent.js"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.3ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_CSS_files_are_non-empty +------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Minigame:_should_serve_lockpicking_script +-------------------------------------------------------------------------------------- +Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/lockpicking-game-phaser.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_CSS:_should_serve_files_with_correct_MIME_type +------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Security:_should_prevent_directory_traversal_in_CSS +------------------------------------------------------------------------------------------------ +Started GET "/break_escape/css/../../config/database.yml" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/database.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Assets:_should_serve_audio_with_correct_MIME_type +---------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_CSS:_should_return_404_for_non-existent_files +------------------------------------------------------------------------------------------ +Started GET "/break_escape/css/non-existent.css" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"non-existent.css"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_image_files_are_non-empty +--------------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_JS:_should_serve_core_game_module +------------------------------------------------------------------------------ +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Assets:_should_serve_PNG_tiles_with_correct_MIME_type +-------------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_CSS:_should_serve_with_inline_disposition +-------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_JS:_should_serve_nested_files +-------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Security:_should_prevent_directory_traversal_in_assets +--------------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/../../config/database.yml" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/database.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.1ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Phaser:_main_JS_imports_GAME_CONFIG +-------------------------------------------------------------------------------- +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Assets:_should_return_404_for_non-existent_files +--------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/non-existent.mp3" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/non-existent.mp3"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_JavaScript_files_are_non-empty +-------------------------------------------------------------------------------------- +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Assets:_should_serve_nested_files +------------------------------------------------------------------------------ +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Phaser:_constants_define_GAME_CONFIG_with_baseURL +---------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Security:_should_prevent_directory_traversal_in_JS +----------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/../../config/secrets.yml" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/secrets.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Headers:_should_set_Content-Disposition_to_inline +---------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Minigame:_should_serve_lockpicking_sounds +-------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_click.mp3" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_click.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_click.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_success.mp3" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_success.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_success.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_HTML:_should_return_404_for_non-existent_files +------------------------------------------------------------------------------------------- +Started GET "/break_escape/non-existent.html" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 + +ActionController::RoutingError (No route matches [GET] "/break_escape/non-existent.html"): + + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Headers:_should_include_Cache-Control +---------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.2ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Phaser:_game.js_has_asset_references_without_prefix +------------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Routes:_should_capture_complex_paths_with_segments +----------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:25:14 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + ActiveRecord::InternalMetadata Load (0.1ms) 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.0ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC + TRANSACTION (0.0ms) begin transaction +  (0.1ms) PRAGMA foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys = ON +  (0.0ms) PRAGMA foreign_keys = OFF + Fixtures Load (0.1ms) 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-25 16:25:18', '2025-11-25 16:25:18'); +INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-25 16:25:18', '2025-11-25 16:25:18'); +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-25 16:25:18', '2025-11-25 16:25:18'); +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-25 16:25:18', '2025-11-25 16:25:18') +  (0.0ms) PRAGMA defer_foreign_keys = 0 +  (0.0ms) PRAGMA foreign_keys = 1 + TRANSACTION (1.6ms) commit transaction +  (0.0ms) PRAGMA foreign_key_check + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Minigame:_should_serve_lockpicking_sounds +-------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (1.7ms) +Completed 200 OK in 3ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_click.mp3" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_click.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_click.mp3 (0.1ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_success.mp3" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_success.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_success.mp3 (0.1ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Headers:_should_set_Content-Disposition_to_inline +---------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Assets:_should_return_404_for_non-existent_files +--------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/non-existent.mp3" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/non-existent.mp3"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 2ms (Views: 2.0ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Headers:_should_include_Cache-Control +---------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Minigame:_should_serve_lockpicking_script +-------------------------------------------------------------------------------------- +Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/lockpicking-game-phaser.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Assets:_should_serve_nested_files +------------------------------------------------------------------------------ +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Phaser:_game.js_has_asset_references_without_prefix +------------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_CSS:_should_serve_with_inline_disposition +-------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Security:_should_prevent_directory_traversal_in_JS +----------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/../../config/secrets.yml" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/secrets.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_JS:_should_serve_files_with_correct_MIME_type +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Security:_should_prevent_directory_traversal_in_assets +--------------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/../../config/database.yml" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/database.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Assets:_should_serve_audio_with_correct_MIME_type +---------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_CSS:_should_serve_files_with_correct_MIME_type +------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_image_files_are_non-empty +--------------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_JS:_should_serve_nested_files +-------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Routes:_should_capture_complex_paths_with_segments +----------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_JS:_should_return_404_for_non-existent_files +----------------------------------------------------------------------------------------- +Started GET "/break_escape/js/non-existent.js" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"non-existent.js"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_audio_files_are_non-empty +--------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Phaser:_main_JS_imports_GAME_CONFIG +-------------------------------------------------------------------------------- +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_HTML:_should_return_404_for_non-existent_files +------------------------------------------------------------------------------------------- +Started GET "/break_escape/non-existent.html" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 + +ActionController::RoutingError (No route matches [GET] "/break_escape/non-existent.html"): + + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Security:_should_prevent_directory_traversal_in_CSS +------------------------------------------------------------------------------------------------ +Started GET "/break_escape/css/../../config/database.yml" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/database.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Phaser:_constants_define_GAME_CONFIG_with_baseURL +---------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Headers:_should_include_Content-Length +----------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_CSS:_should_return_404_for_non-existent_files +------------------------------------------------------------------------------------------ +Started GET "/break_escape/css/non-existent.css" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"non-existent.css"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_HTML:_should_serve_test_files_with_correct_MIME_type +------------------------------------------------------------------------------------------------- +Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as HTML + Parameters: {"filename"=>"test-assets"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/test-assets.html (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_CSS_files_are_non-empty +------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Routes:_should_handle_files_with_multiple_dots +------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door_sheet_32.png" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_sheet_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_sheet_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Assets:_should_serve_PNG_tiles_with_correct_MIME_type +-------------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Routes:_should_capture_full_filename_with_extension +------------------------------------------------------------------------------------------------ +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_JS:_should_serve_core_game_module +------------------------------------------------------------------------------ +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_JavaScript_files_are_non-empty +-------------------------------------------------------------------------------------- +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_should_load_GAME_CONFIG_with_proper_baseURL +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_door_tile_image +--------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door.png" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_CSS_files_should_be_accessible_from_main_game +-------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_key-operations_minigame_module +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/minigames/lockpicking/key-operations.js" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/key-operations.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/key-operations.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_route_constraints_correctly_capture_file_extensions +-------------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_security:_cannot_access_files_outside_break_escape_directory +----------------------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/../../config/secrets.yml" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/secrets.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/js/../../config/database.yml" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/database.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/../../config/secrets.yml" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/secrets.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_asset_paths_work_without_assets_prefix_in_load_calls +--------------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_baseURL_prevents_duplicate_asset_paths +------------------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_complete_asset_loading_path_for_lockpicking +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/lockpicking-game-phaser.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_click.mp3" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_click.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_click.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_overtension.mp3" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_overtension.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_overtension.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_reset.mp3" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_reset.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_reset.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_set.mp3" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_set.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_set.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_success.mp3" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_success.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_success.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_tension.mp3" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_tension.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_tension.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_wrong.mp3" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_wrong.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_wrong.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_test_asset_page_loads_correctly +------------------------------------------------------------------------------ +Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as HTML + Parameters: {"filename"=>"test-assets"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/test-assets.html (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_load_all_required_game_files_in_correct_order +--------------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_lockpicking_minigame +-------------------------------------------------------------------------------- +Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/lockpicking-game-phaser.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.3ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_sound_manager_module +-------------------------------------------------------------------------------- +Started GET "/break_escape/js/systems/sound-manager.js" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/sound-manager.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/sound-manager.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_game_core_with_asset_references +------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_all_response_headers_are_correct +------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_minigame_starters +----------------------------------------------------------------------------- +Started GET "/break_escape/js/systems/minigame-starters.js" for 127.0.0.1 at 2025-11-25 16:25:18 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/minigame-starters.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/minigame-starters.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------- +BreakEscapeTest: test_it_has_a_version_number +--------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_sync_state_should_update_player_state_for_current_room +--------------------------------------------------------------------------------------------- + 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.0ms) 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.2ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.007353"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.007266"], ["updated_at", "2025-11-25 16:25:19.007266"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#sync_state as HTML + Parameters: {"currentRoom"=>"reception", "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.0ms) 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.0ms) 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::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 3ms (Views: 0.1ms | ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------- +BreakEscape::GamesControllerTest: test_should_show_game +------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.016247"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.016201"], ["updated_at", "2025-11-25 16:25:19.016201"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.5ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.7ms | GC: 0.0ms) +Completed 200 OK in 2ms (Views: 0.9ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::GamesControllerTest: test_ink_endpoint_should_return_404_for_non-existent_NPC +------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.020248"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.020208"], ["updated_at", "2025-11-25 16:25:19.020208"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=non-existent" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"non-existent", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: non-existent +[BreakEscape] No NPCs found in scenario data +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_inventory_endpoint_should_add_items +-------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.022546"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.022509"], ["updated_at", "2025-11-25 16:25:19.022509"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[{\"id\":\"note_1\",\"type\":\"note\",\"name\":\"Test Note\",\"takeable\":true}]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:25:19.023026"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/inventory" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#inventory as HTML + Parameters: {"action_type"=>"add", "item"=>{"type"=>"note", "name"=>"Test Note", "id"=>"note_1"}, "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] inventory endpoint: action=add, item=#"note", "name"=>"Test Note", "id"=>"note_1"} permitted: false> +[BreakEscape] validate_item_collectible: type=note, id=note_1, name=Test Note +[BreakEscape] Item collection valid: note +[BreakEscape] Adding item to inventory: note / Test Note + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"note\",\"name\":\"Test Note\",\"id\":\"note_1\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:25:19.024863"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Item added successfully. Current inventory: [{"type"=>"note", "name"=>"Test Note", "id"=>"note_1"}] +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_show_should_return_HTML_with_game_container +---------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.026183"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.026145"], ["updated_at", "2025-11-25 16:25:19.026145"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.2ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.2ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.3ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_show_should_inject_game_configuration +---------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.029340"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.029297"], ["updated_at", "2025-11-25 16:25:19.029297"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.1ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.2ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.3ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_ink_endpoint_should_require_npc_parameter +-------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.032086"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.032046"], ["updated_at", "2025-11-25 16:25:19.032046"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 400 Bad Request in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_scenario_endpoint_should_return_JSON +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.034117"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.034079"], ["updated_at", "2025-11-25 16:25:19.034079"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#scenario as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_unlock_endpoint_should_accept_correct_pin_code +------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.036160"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.036123"], ["updated_at", "2025-11-25 16:25:19.036123"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"room", "targetId"=>"office", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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=room, id=office, attempt=1234, method=pin +[BreakEscape] Object not found: office +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_unlock_endpoint_should_reject_invalid_attempts +------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.038311"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.038272"], ["updated_at", "2025-11-25 16:25:19.038272"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"room", "targetId"=>"office", "attempt"=>"wrong_code", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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=room, id=office, attempt=wrong_code, method=pin +[BreakEscape] Object not found: office +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::GamesControllerTest: test_ink_endpoint_should_return_404_for_NPC_without_story_file +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.040300"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.040264"], ["updated_at", "2025-11-25 16:25:19.040264"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=missing-npc" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"missing-npc", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: missing-npc +[BreakEscape] No NPCs found in scenario data +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlocked_container:_should_grant_access_without_validation +---------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.042638"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.042572"], ["updated_at", "2025-11-25 16:25:19.042572"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:19.044450"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_incorrect_PIN_should_fail +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.045978"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.045912"], ["updated_at", "2025-11-25 16:25:19.045912"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_containers +----------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.048193"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.048131"], ["updated_at", "2025-11-25 16:25:19.048131"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:19.051928"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 3ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 2.0ms) + TRANSACTION (0.0ms) 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.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.053396"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.053322"], ["updated_at", "2025-11-25 16:25:19.053322"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:25:19.054013"], ["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-25 16:25:19 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:19.055845"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_password_lock:_empty_attempt_should_fail +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.057337"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.057276"], ["updated_at", "2025-11-25 16:25:19.057276"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_incorrect_PIN_should_fail +--------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.059780"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.059685"], ["updated_at", "2025-11-25 16:25:19.059685"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: false +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.1ms) + 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.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_for_non-existent_NPC +----------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.062282"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.062216"], ["updated_at", "2025-11-25 16:25:19.062216"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_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\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:25:19.062815"], ["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-25 16:25:19 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=fake_npc, target=office_pin +[BreakEscape] NPC not found: fake_npc +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_key_lock:_should_trust_client_validation +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.2ms) 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-25 16:25:19.065085"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.065021"], ["updated_at", "2025-11-25 16:25:19.065021"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_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\":[],\"inventory\":[{\"id\":\"office_key\",\"type\":\"key\",\"name\":\"Office Key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:25:19.065713"], ["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-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=key, requires=office_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=, is_match=true +[BreakEscape] Key office_key found in inventory: true +[BreakEscape] Key validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) 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\":[{\"id\":\"office_key\",\"type\":\"key\",\"name\":\"Office Key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:25:19.067314"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_password_lock:_incorrect_password_should_fail +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.068710"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.068650"], ["updated_at", "2025-11-25 16:25:19.068650"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"wrongpassword", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: false +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_unlockable_is_not_an_array +-------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.071066"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.070991"], ["updated_at", "2025-11-25 16:25:19.070991"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:25:19.071627"], ["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-25 16:25:19 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_bluetooth_lock:_should_trust_client_validation +------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.073710"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.073648"], ["updated_at", "2025-11-25 16:25:19.073648"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"terminal_bluetooth", "attempt"=>nil, "method"=>"bluetooth", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:19.075675"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_already-unlocked_container_accepts_method='unlocked' +---------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.077248"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.077182"], ["updated_at", "2025-11-25 16:25:19.077182"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:25:19.077836"], ["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-25 16:25:19 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:19.079792"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"npc_safe", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_unlock_response_should_not_expose_'requires'_field_for_exploitable_locks +----------------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.2ms) 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-25 16:25:19.082668"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.082604"], ["updated_at", "2025-11-25 16:25:19.082604"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:19.084364"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_lockpick:_should_trust_client_validation +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.085643"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.085582"], ["updated_at", "2025-11-25 16:25:19.085582"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"box_lockpick", "attempt"=>nil, "method"=>"lockpick", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:19.087351"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlocked_door:_should_grant_access_without_validation +----------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.088503"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.088431"], ["updated_at", "2025-11-25 16:25:19.088431"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=false, lockType=, requires= +[BreakEscape] Door is unlocked in scenario data, granting access + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:19.090151"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_NPC_unlock_adds_door_to_unlockedRooms +------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.091547"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.091481"], ["updated_at", "2025-11-25 16:25:19.091481"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:25:19.092083"], ["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-25 16:25:19 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin +[BreakEscape] NPC unlock validated: helper_npc can unlock office_pin + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:19.093662"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_player_has_not_encountered_NPC +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.095287"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.095221"], ["updated_at", "2025-11-25 16:25:19.095221"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:25:19.095838"], ["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-25 16:25:19 +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.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin +[BreakEscape] Player has not encountered NPC: helper_npc +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_container_with_password_lock:_correct_password_should_unlock +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.098270"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.098205"], ["updated_at", "2025-11-25 16:25:19.098205"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"secret123", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:19.099901"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_multiple_unlock_attempts_should_update_state_correctly +------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.101241"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.101176"], ["updated_at", "2025-11-25 16:25:19.101176"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:19.102832"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:19.105190"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.2ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.2ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:19.107185"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.2ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlock_non-existent_object_should_fail +-------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.108595"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.108528"], ["updated_at", "2025-11-25 16:25:19.108528"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_RFID_lock:_should_trust_client_validation +-------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.111016"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.110953"], ["updated_at", "2025-11-25 16:25:19.110953"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"door_rfid", "attempt"=>nil, "method"=>"rfid", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:19.112724"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_key_lock:_should_trust_client_validation +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.114053"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.113965"], ["updated_at", "2025-11-25 16:25:19.113965"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"drawer_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:19.115787"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_correct_PIN_should_unlock +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.116913"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.116852"], ["updated_at", "2025-11-25 16:25:19.116852"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:19.118525"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_unlock_non-existent_door_should_fail +------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.119906"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.119845"], ["updated_at", "2025-11-25 16:25:19.119845"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_locked_container_cannot_be_bypassed_with_method='unlocked' +-------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.122005"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.121944"], ["updated_at", "2025-11-25 16:25:19.121944"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlock_with_invalid_method_should_fail +-------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.124362"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.124285"], ["updated_at", "2025-11-25 16:25:19.124285"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: invalid_method +[BreakEscape] SECURITY VIOLATION: No valid unlock method for LOCKED door: office_pin, method=invalid_method +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_password_lock:_correct_password_should_unlock +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.126542"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.126480"], ["updated_at", "2025-11-25 16:25:19.126480"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:19.128232"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_doors +------------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.129715"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.129649"], ["updated_at", "2025-11-25 16:25:19.129649"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=false, lockType=, requires= +[BreakEscape] Door is unlocked in scenario data, granting access + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) 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-25 16:25:19.131578"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_password_lock:_case_sensitivity +----------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.132935"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.132873"], ["updated_at", "2025-11-25 16:25:19.132873"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"OpenSesame", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: false +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) 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.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.135259"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.135196"], ["updated_at", "2025-11-25 16:25:19.135196"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:25:19.135779"], ["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-25 16:25:19 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_correct_PIN_should_unlock +--------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.138177"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.138099"], ["updated_at", "2025-11-25 16:25:19.138099"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:19.139755"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_locked_door_cannot_be_bypassed_with_method='unlocked' +--------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.141192"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.141128"], ["updated_at", "2025-11-25 16:25:19.141128"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: unlocked +[BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED door: office_pin +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_already-unlocked_door_accepts_method='unlocked' +----------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.143491"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.143428"], ["updated_at", "2025-11-25 16:25:19.143428"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:25:19.144026"], ["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-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"ceo", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=password, requires=TopSecret123 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=ceo +[BreakEscape] NPC unlock validated: helper_npc can unlock ceo + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:19.145607"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"ceo", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_NPC_can_unlock_door_if_player_has_encountered_them_and_NPC_has_permission +------------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.148281"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.148216"], ["updated_at", "2025-11-25 16:25:19.148216"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:25:19.148815"], ["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-25 16:25:19 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin +[BreakEscape] NPC unlock validated: helper_npc can unlock office_pin + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:19.150335"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlock_same_door_twice_should_be_idempotent +------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.151656"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.151593"], ["updated_at", "2025-11-25 16:25:19.151593"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:19.153223"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 2ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.6ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.2ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_biometric_lock:_should_trust_client_validation +------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:19.156755"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.156688"], ["updated_at", "2025-11-25 16:25:19.156688"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"scanner_biometric", "attempt"=>nil, "method"=>"biometric", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) 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-25 16:25:19.158560"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_unlock_response_should_filter_requires_from_contents +-------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.2ms) 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-25 16:25:19.159969"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.159902"], ["updated_at", "2025-11-25 16:25:19.159902"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:19.161715"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_OGG_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_SVG_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_CSS_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_WAV_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_JavaScript_content_type +----------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_MP3_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_HTML_content_type +----------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_JPEG_content_type +----------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_JSON_content_type +----------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_handles_multiple_dots_in_filename +---------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_PNG_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_returns_octet-stream_for_unknown_extensions +-------------------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_WOFF2_font_content_type +----------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_is_case_insensitive +-------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_TTF_font_content_type +--------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_GIF_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_WOFF_font_content_type +---------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_get_index +---------------------------------------------------------- +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.0ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" = ? [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.2ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 5.5ms | GC: 0.2ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 5.5ms | GC: 0.2ms) +Completed 200 OK in 6ms (Views: 5.5ms | ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.2ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_index_should_display_published_missions +--------------------------------------------------------------------------------- +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.0ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" = ? [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 0.6ms | GC: 0.1ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.6ms | GC: 0.1ms) +Completed 200 OK in 1ms (Views: 0.7ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_show_published_mission +----------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] +Started GET "/break_escape/missions/418560898" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::MissionsController#show as HTML + Parameters: {"id"=>"418560898"} + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."player_type" = ? AND "break_escape_games"."player_id" = ? AND "break_escape_games"."mission_id" = ? LIMIT ? [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) 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", "{\"scenario_brief\":\"Hi! You are a cyber investigator tasked with uncovering evidence of corporate espionage. Anonymous tips suggest the CEO has been selling company secrets, but you need proof.\",\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office1\"},\"npcs\":[{\"id\":\"neye_eve\",\"displayName\":\"Neye Eve\",\"storyPath\":\"scenarios/ink/neye-eve.json\",\"avatar\":\"assets/npc/avatars/npc_adversary.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\"},{\"id\":\"gossip_girl\",\"displayName\":\"Gossip Girl\",\"storyPath\":\"scenarios/ink/gossip-girl.json\",\"avatar\":\"assets/npc/avatars/npc_neutral.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"timedMessages\":[{\"delay\":5000,\"message\":\"Hey! 👋 Got any juicy gossip for me today?\",\"type\":\"text\"}]},{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"storyPath\":\"scenarios/ink/helper-npc.json\",\"avatar\":\"assets/npc/avatars/npc_helper.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"unlockable\":[\"secure_vault\",\"ceo\"],\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":15000},{\"eventPattern\":\"door_unlocked\",\"targetKnot\":\"on_door_unlocked\",\"cooldown\":8000},{\"eventPattern\":\"door_unlock_attempt\",\"targetKnot\":\"on_door_attempt\",\"cooldown\":12000},{\"eventPattern\":\"object_interacted\",\"targetKnot\":\"on_ceo_desk_interact\",\"condition\":\"data.objectType === 'desk_ceo'\",\"cooldown\":10000},{\"eventPattern\":\"item_picked_up:*\",\"targetKnot\":\"on_item_found\",\"cooldown\":20000},{\"eventPattern\":\"room_entered\",\"targetKnot\":\"on_room_entered\",\"cooldown\":45000,\"maxTriggers\":3},{\"eventPattern\":\"room_discovered\",\"targetKnot\":\"on_room_discovered\",\"cooldown\":15000,\"maxTriggers\":5},{\"eventPattern\":\"room_entered:ceo\",\"targetKnot\":\"on_ceo_office_entered\",\"onceOnly\":true}]}],\"objects\":[{\"type\":\"phone\",\"name\":\"Reception Phone\",\"takeable\":false,\"readable\":true,\"voice\":\"Hi, this is the IT Team. Security breach detected in server room. Changed access code to 4829.\",\"sender\":\"IT Team\",\"timestamp\":\"2:15 AM\",\"observations\":\"The reception phone's message light is blinking urgently\"},{\"type\":\"notes\",\"name\":\"Security Log\",\"takeable\":true,\"readable\":true,\"text\":\"Unusual after-hours access detected:\\n- CEO office: 11:30 PM\\n- Server room: 2:15 AM\\n- CEO office again: 3:45 AM\",\"observations\":\"A concerning security log from last night\"},{\"type\":\"pc\",\"name\":\"Reception Computer\",\"takeable\":false,\"lockType\":\"password\",\"passwordHint\":\"Optional hint text\",\"showHint\":true,\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"requires\":\"secret123\",\"observations\":\"The reception's computer, currently locked\",\"postitNote\":\"Password: secret123\",\"showPostit\":true,\"contents\":[{\"type\":\"text_file\",\"name\":\"Private\",\"takeable\":false,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\"}]},{\"type\":\"tablet\",\"name\":\"Tablet Device\",\"takeable\":true,\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"A locked tablet device that requires Bluetooth pairing\"},{\"type\":\"bluetooth_scanner\",\"name\":\"Bluetooth Scanner\",\"takeable\":true,\"observations\":\"A device for detecting nearby Bluetooth signals\",\"canScanBluetooth\":true},{\"type\":\"key\",\"name\":\"Office Key\",\"takeable\":true,\"key_id\":\"office1_key\",\"keyPins\":[65,25,65,25],\"observations\":\"A key to access the office areas\"},{\"type\":\"pin-cracker\",\"name\":\"PIN Cracker\",\"takeable\":true,\"observations\":\"A sophisticated device that can analyze PIN entry patterns and provide feedback on attempts\"},{\"type\":\"safe\",\"name\":\"Reception Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9573\",\"observations\":\"A small wall safe behind the reception desk. Looks like it needs a 4-digit code.\",\"contents\":[{\"type\":\"notes\",\"name\":\"IT Access Credentials\",\"takeable\":true,\"readable\":true,\"text\":\"Emergency IT Admin Credentials:\\nUsername: admin\\nPassword: ITsecure2024\\n\\nServer Room Backup Code: 4829\\nCEO Office Alarm Override: 1337\",\"observations\":\"Sensitive IT credentials that could be very useful\"}]}]},\"office1\":{\"type\":\"room_office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office1_key\",\"keyPins\":[65,25,65,25],\"difficulty\":\"easy\",\"door_sign\":\"4A Hot Desks\",\"connections\":{\"north\":[\"office2\",\"office3\"],\"south\":\"reception\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"requires\":\"password\",\"hasFingerprint\":true,\"fingerprintOwner\":\"ceo\",\"fingerprintDifficulty\":\"medium\",\"observations\":\"A computer with a cybersecurity alert on screen. There might be fingerprints on the keyboard.\"},{\"type\":\"notes\",\"name\":\"IT Memo\",\"takeable\":true,\"readable\":true,\"text\":\"URGENT: Multiple unauthorized access attempts detected from CEO's office IP address\",\"observations\":\"A concerning IT department memo\"},{\"type\":\"fingerprint_kit\",\"name\":\"Fingerprint Kit\",\"takeable\":true,\"observations\":\"A kit used for collecting fingerprints from surfaces\"}]},\"office2\":{\"type\":\"room_office\",\"connections\":{\"north\":\"ceo\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"office2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: office2024\",\"showPostit\":true,\"observations\":\"A standard office computer with a sticky note on the monitor\"},{\"type\":\"notes\",\"name\":\"Shredded Document\",\"takeable\":true,\"readable\":true,\"text\":\"Partially readable: '...offshore account...transfer complete...delete all traces...'\",\"observations\":\"A partially shredded document that someone failed to dispose of properly\"},{\"type\":\"key\",\"name\":\"CEO Office Key\",\"takeable\":true,\"key_id\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"observations\":\"A spare key to the CEO's office, carelessly left behind\"}]},\"office3\":{\"type\":\"room_office\",\"connections\":{\"north\":\"server1\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"IT Staff Computer\",\"takeable\":false,\"requires\":\"bluetooth\",\"lockType\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"An IT staff computer showing network security logs\"},{\"type\":\"notes\",\"name\":\"Network Logs\",\"takeable\":true,\"readable\":true,\"text\":\"Large data transfers detected to unknown external IPs - All originating from CEO's office\",\"observations\":\"Suspicious network activity logs\"}]},\"ceo\":{\"type\":\"room_ceo\",\"connections\":{\"north\":\"closet\",\"south\":\"office2\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"difficulty\":\"easy\",\"objects\":[{\"type\":\"pc\",\"name\":\"CEO Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"ceo2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: ceo2024\",\"showPostit\":true,\"observations\":\"The CEO's laptop, still warm - recently used. A sticky note is attached to the screen.\"},{\"type\":\"suitcase\",\"name\":\"CEO Briefcase\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"difficulty\":\"medium\",\"observations\":\"An expensive leather briefcase with a sturdy lock\",\"contents\":[{\"type\":\"notes\",\"name\":\"Private Note\",\"takeable\":true,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\",\"observations\":\"A hastily written note on expensive paper\"},{\"type\":\"key\",\"name\":\"Safe Key\",\"takeable\":true,\"key_id\":\"safe_key\",\"keyPins\":[52,29,44,37],\"observations\":\"A heavy-duty safe key hidden behind server equipment\"}]},{\"type\":\"phone\",\"name\":\"CEO Phone\",\"takeable\":false,\"readable\":true,\"text\":\"Recent calls: 'Offshore Bank', 'Unknown', 'Data Buyer'\",\"sender\":\"Call Log\",\"timestamp\":\"Last 24 hours\",\"observations\":\"The CEO's phone shows suspicious recent calls\"}]},\"closet\":{\"type\":\"room_closet\",\"connections\":{\"south\":\"ceo\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"7391\",\"objects\":[{\"type\":\"safe\",\"name\":\"Hidden Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"safe_key\",\"keyPins\":[52,29,44,37],\"difficulty\":\"hard\",\"observations\":\"A well-hidden wall safe behind a painting\",\"contents\":[{\"type\":\"notes\",\"name\":\"Incriminating Documents\",\"takeable\":true,\"readable\":true,\"text\":\"Contract for sale of proprietary technology\\nBank transfers from competing companies\\nDetails of upcoming corporate espionage operations\",\"observations\":\"A folder containing damning evidence of corporate espionage. Congratulations! You've recovered the incriminating documents. flag{ceo_exfil_flag}\"}]}]},\"server1\":{\"type\":\"room_servers\",\"connections\":{\"south\":\"office3\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"4829\",\"objects\":[{\"type\":\"pc\",\"name\":\"Server Terminal\",\"takeable\":false,\"observations\":\"The main server terminal showing massive data exfiltration\"},{\"type\":\"key\",\"name\":\"Briefcase Key\",\"takeable\":true,\"key_id\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.177020"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.176368"], ["updated_at", "2025-11-25 16:25:19.176368"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Redirected to http://www.example.com/break_escape/games/1 +Completed 302 Found in 2ms (ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_create_game_and_redirect_when_showing_mission +---------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Count (0.0ms) SELECT COUNT(*) FROM "break_escape_games" +Started GET "/break_escape/missions/418560898" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::MissionsController#show as HTML + Parameters: {"id"=>"418560898"} + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."player_type" = ? AND "break_escape_games"."player_id" = ? AND "break_escape_games"."mission_id" = ? LIMIT ? [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) 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", "{\"scenario_brief\":\"Hi! You are a cyber investigator tasked with uncovering evidence of corporate espionage. Anonymous tips suggest the CEO has been selling company secrets, but you need proof.\",\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office1\"},\"npcs\":[{\"id\":\"neye_eve\",\"displayName\":\"Neye Eve\",\"storyPath\":\"scenarios/ink/neye-eve.json\",\"avatar\":\"assets/npc/avatars/npc_adversary.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\"},{\"id\":\"gossip_girl\",\"displayName\":\"Gossip Girl\",\"storyPath\":\"scenarios/ink/gossip-girl.json\",\"avatar\":\"assets/npc/avatars/npc_neutral.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"timedMessages\":[{\"delay\":5000,\"message\":\"Hey! 👋 Got any juicy gossip for me today?\",\"type\":\"text\"}]},{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"storyPath\":\"scenarios/ink/helper-npc.json\",\"avatar\":\"assets/npc/avatars/npc_helper.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"unlockable\":[\"secure_vault\",\"ceo\"],\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":15000},{\"eventPattern\":\"door_unlocked\",\"targetKnot\":\"on_door_unlocked\",\"cooldown\":8000},{\"eventPattern\":\"door_unlock_attempt\",\"targetKnot\":\"on_door_attempt\",\"cooldown\":12000},{\"eventPattern\":\"object_interacted\",\"targetKnot\":\"on_ceo_desk_interact\",\"condition\":\"data.objectType === 'desk_ceo'\",\"cooldown\":10000},{\"eventPattern\":\"item_picked_up:*\",\"targetKnot\":\"on_item_found\",\"cooldown\":20000},{\"eventPattern\":\"room_entered\",\"targetKnot\":\"on_room_entered\",\"cooldown\":45000,\"maxTriggers\":3},{\"eventPattern\":\"room_discovered\",\"targetKnot\":\"on_room_discovered\",\"cooldown\":15000,\"maxTriggers\":5},{\"eventPattern\":\"room_entered:ceo\",\"targetKnot\":\"on_ceo_office_entered\",\"onceOnly\":true}]}],\"objects\":[{\"type\":\"phone\",\"name\":\"Reception Phone\",\"takeable\":false,\"readable\":true,\"voice\":\"Hi, this is the IT Team. Security breach detected in server room. Changed access code to 4829.\",\"sender\":\"IT Team\",\"timestamp\":\"2:15 AM\",\"observations\":\"The reception phone's message light is blinking urgently\"},{\"type\":\"notes\",\"name\":\"Security Log\",\"takeable\":true,\"readable\":true,\"text\":\"Unusual after-hours access detected:\\n- CEO office: 11:30 PM\\n- Server room: 2:15 AM\\n- CEO office again: 3:45 AM\",\"observations\":\"A concerning security log from last night\"},{\"type\":\"pc\",\"name\":\"Reception Computer\",\"takeable\":false,\"lockType\":\"password\",\"passwordHint\":\"Optional hint text\",\"showHint\":true,\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"requires\":\"secret123\",\"observations\":\"The reception's computer, currently locked\",\"postitNote\":\"Password: secret123\",\"showPostit\":true,\"contents\":[{\"type\":\"text_file\",\"name\":\"Private\",\"takeable\":false,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\"}]},{\"type\":\"tablet\",\"name\":\"Tablet Device\",\"takeable\":true,\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"A locked tablet device that requires Bluetooth pairing\"},{\"type\":\"bluetooth_scanner\",\"name\":\"Bluetooth Scanner\",\"takeable\":true,\"observations\":\"A device for detecting nearby Bluetooth signals\",\"canScanBluetooth\":true},{\"type\":\"key\",\"name\":\"Office Key\",\"takeable\":true,\"key_id\":\"office1_key\",\"keyPins\":[65,25,65,25],\"observations\":\"A key to access the office areas\"},{\"type\":\"pin-cracker\",\"name\":\"PIN Cracker\",\"takeable\":true,\"observations\":\"A sophisticated device that can analyze PIN entry patterns and provide feedback on attempts\"},{\"type\":\"safe\",\"name\":\"Reception Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9573\",\"observations\":\"A small wall safe behind the reception desk. Looks like it needs a 4-digit code.\",\"contents\":[{\"type\":\"notes\",\"name\":\"IT Access Credentials\",\"takeable\":true,\"readable\":true,\"text\":\"Emergency IT Admin Credentials:\\nUsername: admin\\nPassword: ITsecure2024\\n\\nServer Room Backup Code: 4829\\nCEO Office Alarm Override: 1337\",\"observations\":\"Sensitive IT credentials that could be very useful\"}]}]},\"office1\":{\"type\":\"room_office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office1_key\",\"keyPins\":[65,25,65,25],\"difficulty\":\"easy\",\"door_sign\":\"4A Hot Desks\",\"connections\":{\"north\":[\"office2\",\"office3\"],\"south\":\"reception\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"requires\":\"password\",\"hasFingerprint\":true,\"fingerprintOwner\":\"ceo\",\"fingerprintDifficulty\":\"medium\",\"observations\":\"A computer with a cybersecurity alert on screen. There might be fingerprints on the keyboard.\"},{\"type\":\"notes\",\"name\":\"IT Memo\",\"takeable\":true,\"readable\":true,\"text\":\"URGENT: Multiple unauthorized access attempts detected from CEO's office IP address\",\"observations\":\"A concerning IT department memo\"},{\"type\":\"fingerprint_kit\",\"name\":\"Fingerprint Kit\",\"takeable\":true,\"observations\":\"A kit used for collecting fingerprints from surfaces\"}]},\"office2\":{\"type\":\"room_office\",\"connections\":{\"north\":\"ceo\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"office2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: office2024\",\"showPostit\":true,\"observations\":\"A standard office computer with a sticky note on the monitor\"},{\"type\":\"notes\",\"name\":\"Shredded Document\",\"takeable\":true,\"readable\":true,\"text\":\"Partially readable: '...offshore account...transfer complete...delete all traces...'\",\"observations\":\"A partially shredded document that someone failed to dispose of properly\"},{\"type\":\"key\",\"name\":\"CEO Office Key\",\"takeable\":true,\"key_id\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"observations\":\"A spare key to the CEO's office, carelessly left behind\"}]},\"office3\":{\"type\":\"room_office\",\"connections\":{\"north\":\"server1\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"IT Staff Computer\",\"takeable\":false,\"requires\":\"bluetooth\",\"lockType\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"An IT staff computer showing network security logs\"},{\"type\":\"notes\",\"name\":\"Network Logs\",\"takeable\":true,\"readable\":true,\"text\":\"Large data transfers detected to unknown external IPs - All originating from CEO's office\",\"observations\":\"Suspicious network activity logs\"}]},\"ceo\":{\"type\":\"room_ceo\",\"connections\":{\"north\":\"closet\",\"south\":\"office2\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"difficulty\":\"easy\",\"objects\":[{\"type\":\"pc\",\"name\":\"CEO Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"ceo2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: ceo2024\",\"showPostit\":true,\"observations\":\"The CEO's laptop, still warm - recently used. A sticky note is attached to the screen.\"},{\"type\":\"suitcase\",\"name\":\"CEO Briefcase\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"difficulty\":\"medium\",\"observations\":\"An expensive leather briefcase with a sturdy lock\",\"contents\":[{\"type\":\"notes\",\"name\":\"Private Note\",\"takeable\":true,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\",\"observations\":\"A hastily written note on expensive paper\"},{\"type\":\"key\",\"name\":\"Safe Key\",\"takeable\":true,\"key_id\":\"safe_key\",\"keyPins\":[52,29,44,37],\"observations\":\"A heavy-duty safe key hidden behind server equipment\"}]},{\"type\":\"phone\",\"name\":\"CEO Phone\",\"takeable\":false,\"readable\":true,\"text\":\"Recent calls: 'Offshore Bank', 'Unknown', 'Data Buyer'\",\"sender\":\"Call Log\",\"timestamp\":\"Last 24 hours\",\"observations\":\"The CEO's phone shows suspicious recent calls\"}]},\"closet\":{\"type\":\"room_closet\",\"connections\":{\"south\":\"ceo\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"7391\",\"objects\":[{\"type\":\"safe\",\"name\":\"Hidden Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"safe_key\",\"keyPins\":[52,29,44,37],\"difficulty\":\"hard\",\"observations\":\"A well-hidden wall safe behind a painting\",\"contents\":[{\"type\":\"notes\",\"name\":\"Incriminating Documents\",\"takeable\":true,\"readable\":true,\"text\":\"Contract for sale of proprietary technology\\nBank transfers from competing companies\\nDetails of upcoming corporate espionage operations\",\"observations\":\"A folder containing damning evidence of corporate espionage. Congratulations! You've recovered the incriminating documents. flag{ceo_exfil_flag}\"}]}]},\"server1\":{\"type\":\"room_servers\",\"connections\":{\"south\":\"office3\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"4829\",\"objects\":[{\"type\":\"pc\",\"name\":\"Server Terminal\",\"takeable\":false,\"observations\":\"The main server terminal showing massive data exfiltration\"},{\"type\":\"key\",\"name\":\"Briefcase Key\",\"takeable\":true,\"key_id\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.180365"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.179660"], ["updated_at", "2025-11-25 16:25:19.179660"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Redirected to http://www.example.com/break_escape/games/1 +Completed 302 Found in 2ms (ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Count (0.0ms) SELECT COUNT(*) FROM "break_escape_games" + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------ +BreakEscape::MissionsControllerTest: test_index_should_return_HTML_with_mission_list +------------------------------------------------------------------------------------ +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.0ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" = ? [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 0.5ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.6ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.6ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_removes_objects_and_npcs +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.184085"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.184041"], ["updated_at", "2025-11-25 16:25:19.184041"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_does_not_modify_original +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.185175"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.185132"], ["updated_at", "2025-11-25 16:25:19.185132"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_removes_room_contents +--------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.186154"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.186114"], ["updated_at", "2025-11-25 16:25:19.186114"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------------ +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_preserves_navigation_structure +------------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.187203"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.187164"], ["updated_at", "2025-11-25 16:25:19.187164"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_preserves_lock_requirements +--------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.188155"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.188118"], ["updated_at", "2025-11-25 16:25:19.188118"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------- +BreakEscape::GameTest: test_should_clamp_health_between_0_and_100 +----------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.189314"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.189285"], ["updated_at", "2025-11-25 16:25:19.189285"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":0}"], ["updated_at", "2025-11-25 16:25:19.189846"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------- +BreakEscape::GameTest: test_should_reject_lockpick_unlock_without_lockpick_in_inventory +--------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.190714"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.190687"], ["updated_at", "2025-11-25 16:25:19.190687"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=lockpick +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: lockpick +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=key, scenarioData.type=, is_lockpick=false +[BreakEscape] Lockpick found in inventory: false +[BreakEscape] Lockpick validation result: false +[BreakEscape] validate_unlock returning: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GameTest: test_has_key_in_inventory_should_find_keys_by_key_id +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.191825"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.191797"], ["updated_at", "2025-11-25 16:25:19.191797"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Checking for key office1_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=true +[BreakEscape] Key office1_key found in inventory: true +[BreakEscape] Checking for key wrong_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=false +[BreakEscape] Key wrong_key found in inventory: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------- +BreakEscape::GameTest: test_should_track_inventory +-------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.192809"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.192781"], ["updated_at", "2025-11-25 16:25:19.192781"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"key\",\"name\":\"Test Key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:25:19.193243"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::GameTest: test_should_allow_access_to_unlocked_doors_regardless_of_method +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.194183"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.194155"], ["updated_at", "2025-11-25 16:25:19.194155"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=reception, attempt=, method=unlocked +[BreakEscape] Door already unlocked in player state, granting access + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------- +BreakEscape::GameTest: test_should_belong_to_player_and_mission +--------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.195148"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.195121"], ["updated_at", "2025-11-25 16:25:19.195121"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------- +BreakEscape::GameTest: test_has_lockpick_in_inventory_should_not_find_non-lockpick_items +---------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.196106"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.196078"], ["updated_at", "2025-11-25 16:25:19.196078"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=key, scenarioData.type=, is_lockpick=false +[BreakEscape] Lockpick found in inventory: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------- +BreakEscape::GameTest: test_key_takes_precedence_over_lockpick_attempt +---------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.197074"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.197044"], ["updated_at", "2025-11-25 16:25:19.197044"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=key +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office1_key in inventory (2 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=true +[BreakEscape] Key office1_key found in inventory: true +[BreakEscape] Key validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------ +BreakEscape::GameTest: test_lockpick_should_bypass_key_requirement +------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.198052"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.198024"], ["updated_at", "2025-11-25 16:25:19.198024"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=secure_vault, attempt=, method=lockpick +[BreakEscape] Room data: locked=true, lockType=key, requires=vault_master_key +[BreakEscape] Room is LOCKED, method must be valid: lockpick +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=lockpick, scenarioData.type=, is_lockpick=true +[BreakEscape] Lockpick found in inventory: true +[BreakEscape] Lockpick validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------- +BreakEscape::GameTest: test_should_validate_unlock_with_lockpick +---------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.198997"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.198969"], ["updated_at", "2025-11-25 16:25:19.198969"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=lockpick +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: lockpick +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=lockpick, scenarioData.type=, is_lockpick=true +[BreakEscape] Lockpick found in inventory: true +[BreakEscape] Lockpick validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::GameTest: test_should_reject_locked_door_without_any_unlock_method +------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.199971"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.199946"], ["updated_at", "2025-11-25 16:25:19.199946"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method= +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: +[BreakEscape] SECURITY VIOLATION: No valid unlock method for LOCKED door: office1, method= +[BreakEscape] validate_unlock returning: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------- +BreakEscape::GameTest: test_should_unlock_room +---------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.200910"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.200883"], ["updated_at", "2025-11-25 16:25:19.200883"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\",\"office\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:25:19.201316"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------- +BreakEscape::GameTest: test_should_validate_unlock_with_correct_key +------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.202148"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.202121"], ["updated_at", "2025-11-25 16:25:19.202121"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=key +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office1_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=true +[BreakEscape] Key office1_key found in inventory: true +[BreakEscape] Key validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------- +BreakEscape::GameTest: test_should_reject_unlock_without_required_key +--------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.203097"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.203070"], ["updated_at", "2025-11-25 16:25:19.203070"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=key +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office1_key in inventory (1 items) +[BreakEscape] Inventory item: name=Wrong Key, key_id=wrong_key, is_match=false +[BreakEscape] Key office1_key found in inventory: false +[BreakEscape] Key validation result: false +[BreakEscape] validate_unlock returning: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GameTest: test_has_lockpick_in_inventory_should_find_lockpicks +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.204061"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.204033"], ["updated_at", "2025-11-25 16:25:19.204033"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=lockpick, scenarioData.type=, is_lockpick=true +[BreakEscape] Lockpick found in inventory: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------ +BreakEscape::GameTest: test_should_update_health +------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.204981"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.204954"], ["updated_at", "2025-11-25 16:25:19.204954"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":50}"], ["updated_at", "2025-11-25 16:25:19.205401"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_phone-chat-minigame_should_use_Rails_API_endpoint_for_story_loading +-------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.206401"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.206370"], ["updated_at", "2025-11-25 16:25:19.206370"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/phone-chat/phone-chat-minigame.js" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/phone-chat/phone-chat-minigame.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/phone-chat/phone-chat-minigame.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_404_for_NPC_without_story_file +--------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.208153"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.208121"], ["updated_at", "2025-11-25 16:25:19.208121"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=npc-with-no-file" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"npc-with-no-file", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: npc-with-no-file +[BreakEscape] Available NPCs: security_guard (test_room), test-npc (test_room) +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_person-chat-minigame_should_use_Rails_API_endpoint_for_story_loading +--------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.212000"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.211961"], ["updated_at", "2025-11-25 16:25:19.211961"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/person-chat/person-chat-minigame.js?v=10" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"v"=>"10", "path"=>"minigames/person-chat/person-chat-minigame.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/person-chat/person-chat-minigame.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::NPCInkLoadingTest: test_person-chat-portraits_should_import_ASSETS_PATH_from_config +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.213977"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.213944"], ["updated_at", "2025-11-25 16:25:19.213944"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/person-chat/person-chat-portraits.js" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/person-chat/person-chat-portraits.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/person-chat/person-chat-portraits.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------ +BreakEscape::NPCInkLoadingTest: test_npc-barks_should_import_ASSETS_PATH_from_config +------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.215668"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.215636"], ["updated_at", "2025-11-25 16:25:19.215636"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/systems/npc-barks.js" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/npc-barks.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/npc-barks.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_npc-lazy-loader_should_construct_correct_API_endpoint_URL +---------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.217301"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.217269"], ["updated_at", "2025-11-25 16:25:19.217269"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/systems/npc-lazy-loader.js" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/npc-lazy-loader.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/npc-lazy-loader.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_npc-manager_should_load_stories_via_API_endpoint +------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.219004"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.218973"], ["updated_at", "2025-11-25 16:25:19.218973"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/systems/npc-manager.js" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/npc-manager.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/npc-manager.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_ink_endpoint_should_return_application/json_content_type +--------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.220631"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.220600"], ["updated_at", "2025-11-25 16:25:19.220600"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=security_guard" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"security_guard", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: security_guard +[BreakEscape] Found NPC: security_guard with storyPath: scenarios/ink/security-guard.json +[BreakEscape] Serving ink from: /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/scenarios/ink/security-guard.json +Completed 200 OK in 1ms (Views: 0.3ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_phone-chat-ui_should_import_ASSETS_PATH_from_config +---------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.223163"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.223133"], ["updated_at", "2025-11-25 16:25:19.223133"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/phone-chat/phone-chat-ui.js" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/phone-chat/phone-chat-ui.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/phone-chat/phone-chat-ui.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_404_for_non-existent_game +---------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.224780"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.224748"], ["updated_at", "2025-11-25 16:25:19.224748"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/999999/ink?npc=test-npc" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"test-npc", "id"=>"999999"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 999999], ["LIMIT", 1]] +Completed 404 Not Found in 0ms (ActiveRecord: 0.0ms (1 query, 0 cached) | GC: 0.0ms) + +ActiveRecord::RecordNotFound (Couldn't find BreakEscape::Game with 'id'="999999"): + +activerecord (7.2.3) lib/active_record/core.rb:268:in `find' +/home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/controllers/break_escape/games_controller.rb:323:in `set_game' +activesupport (7.2.3) lib/active_support/callbacks.rb:362:in `block in make_lambda' +activesupport (7.2.3) lib/active_support/callbacks.rb:179:in `block in call' +actionpack (7.2.3) lib/abstract_controller/callbacks.rb:34:in `block (2 levels) in ' +activesupport (7.2.3) lib/active_support/callbacks.rb:180:in `call' +activesupport (7.2.3) lib/active_support/callbacks.rb:560:in `block in invoke_before' +activesupport (7.2.3) lib/active_support/callbacks.rb:560:in `each' +activesupport (7.2.3) lib/active_support/callbacks.rb:560:in `invoke_before' +activesupport (7.2.3) lib/active_support/callbacks.rb:119:in `block in run_callbacks' +actiontext (7.2.3) lib/action_text/rendering.rb:25:in `with_renderer' +actiontext (7.2.3) lib/action_text/engine.rb:71:in `block (4 levels) in ' +activesupport (7.2.3) lib/active_support/callbacks.rb:130:in `instance_exec' +activesupport (7.2.3) lib/active_support/callbacks.rb:130:in `block in run_callbacks' +activesupport (7.2.3) lib/active_support/callbacks.rb:141:in `run_callbacks' +actionpack (7.2.3) lib/abstract_controller/callbacks.rb:260:in `process_action' +actionpack (7.2.3) lib/action_controller/metal/rescue.rb:27:in `process_action' +actionpack (7.2.3) lib/action_controller/metal/instrumentation.rb:77:in `block in process_action' +activesupport (7.2.3) lib/active_support/notifications.rb:210:in `block in instrument' +activesupport (7.2.3) lib/active_support/notifications/instrumenter.rb:58:in `instrument' +activesupport (7.2.3) lib/active_support/notifications.rb:210:in `instrument' +actionpack (7.2.3) lib/action_controller/metal/instrumentation.rb:76:in `process_action' +actionpack (7.2.3) lib/action_controller/metal/params_wrapper.rb:259:in `process_action' +activerecord (7.2.3) lib/active_record/railties/controller_runtime.rb:39:in `process_action' +actionpack (7.2.3) lib/abstract_controller/base.rb:152:in `process' +actionview (7.2.3) lib/action_view/rendering.rb:40:in `process' +actionpack (7.2.3) lib/action_controller/metal.rb:252:in `dispatch' +actionpack (7.2.3) lib/action_controller/metal.rb:335:in `dispatch' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:67:in `dispatch' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:50:in `serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:53:in `block in serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:133:in `block in find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `each' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:34:in `serve' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:896:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/static.rb:27:in `call' +railties (7.2.3) lib/rails/engine.rb:535:in `call' +railties (7.2.3) lib/rails/railtie.rb:226:in `public_send' +railties (7.2.3) lib/rails/railtie.rb:226:in `method_missing' +actionpack (7.2.3) lib/action_dispatch/routing/mapper.rb:33:in `block in ' +actionpack (7.2.3) lib/action_dispatch/routing/mapper.rb:62:in `serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:53:in `block in serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:133:in `block in find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `each' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:34:in `serve' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:896:in `call' +rack (3.2.4) lib/rack/tempfile_reaper.rb:20:in `call' +rack (3.2.4) lib/rack/etag.rb:29:in `call' +rack (3.2.4) lib/rack/conditional_get.rb:31:in `call' +rack (3.2.4) lib/rack/head.rb:15:in `call' +actionpack (7.2.3) lib/action_dispatch/http/permissions_policy.rb:38:in `call' +actionpack (7.2.3) lib/action_dispatch/http/content_security_policy.rb:38:in `call' +rack-session (2.1.1) lib/rack/session/abstract/id.rb:274:in `context' +rack-session (2.1.1) lib/rack/session/abstract/id.rb:268:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/cookies.rb:704:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/callbacks.rb:31:in `block in call' +activesupport (7.2.3) lib/active_support/callbacks.rb:101:in `run_callbacks' +actionpack (7.2.3) lib/action_dispatch/middleware/callbacks.rb:30:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/actionable_exceptions.rb:18:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/debug_exceptions.rb:31:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/show_exceptions.rb:32:in `call' +railties (7.2.3) lib/rails/rack/logger.rb:41:in `call_app' +railties (7.2.3) lib/rails/rack/logger.rb:29:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/remote_ip.rb:96:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/request_id.rb:33:in `call' +rack (3.2.4) lib/rack/method_override.rb:28:in `call' +rack (3.2.4) lib/rack/runtime.rb:24:in `call' +activesupport (7.2.3) lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/executor.rb:16:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/static.rb:27:in `call' +rack (3.2.4) lib/rack/sendfile.rb:131:in `call' +railties (7.2.3) lib/rails/engine.rb:535:in `call' +rack-test (2.2.0) lib/rack/test.rb:360:in `process_request' +rack-test (2.2.0) lib/rack/test.rb:153:in `request' +actionpack (7.2.3) lib/action_dispatch/testing/integration.rb:287:in `process' +actionpack (7.2.3) lib/action_dispatch/testing/integration.rb:19:in `get' +actionpack (7.2.3) lib/action_dispatch/testing/integration.rb:378:in `get' +/home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/test/integration/npc_ink_loading_test.rb:155:in `block in ' +minitest (5.26.2) lib/minitest/test.rb:95:in `block (2 levels) in run' +minitest (5.26.2) lib/minitest/test.rb:191:in `capture_exceptions' +minitest (5.26.2) lib/minitest/test.rb:90:in `block in run' +minitest (5.26.2) lib/minitest.rb:383:in `time_it' +minitest (5.26.2) lib/minitest/test.rb:89:in `run' +activesupport (7.2.3) lib/active_support/executor/test_helper.rb:5:in `block in run' +activesupport (7.2.3) lib/active_support/execution_wrapper.rb:104:in `perform' +activesupport (7.2.3) lib/active_support/executor/test_helper.rb:5:in `run' +minitest (5.26.2) lib/minitest.rb:1224:in `run_one_method' +minitest (5.26.2) lib/minitest.rb:463:in `run_one_method' +minitest (5.26.2) lib/minitest.rb:450:in `block (2 levels) in run' +minitest (5.26.2) lib/minitest.rb:446:in `each' +minitest (5.26.2) lib/minitest.rb:446:in `block in run' +minitest (5.26.2) lib/minitest.rb:488:in `on_signal' +minitest (5.26.2) lib/minitest.rb:475:in `with_info_handler' +minitest (5.26.2) lib/minitest.rb:445:in `run' +railties (7.2.3) lib/rails/test_unit/line_filtering.rb:10:in `run' +minitest (5.26.2) lib/minitest.rb:347:in `block in __run' +minitest (5.26.2) lib/minitest.rb:347:in `map' +minitest (5.26.2) lib/minitest.rb:347:in `__run' +minitest (5.26.2) lib/minitest.rb:302:in `run' +minitest (5.26.2) lib/minitest.rb:86:in `block in autorun' + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_bad_request_if_npc_parameter_missing +--------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.356590"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.356538"], ["updated_at", "2025-11-25 16:25:19.356538"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 400 Bad Request in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_404_for_non-existent_NPC +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.359143"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.359105"], ["updated_at", "2025-11-25 16:25:19.359105"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=non-existent-npc" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"non-existent-npc", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: non-existent-npc +[BreakEscape] Available NPCs: security_guard (test_room), test-npc (test_room) +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_ink_endpoint_should_work_with_underscored_NPC_IDs +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.361295"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.361263"], ["updated_at", "2025-11-25 16:25:19.361263"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=npc-with-underscores" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"npc-with-underscores", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: npc-with-underscores +[BreakEscape] Available NPCs: security_guard (test_room), test-npc (test_room) +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------- +BreakEscape::MissionTest: test_should_validate_presence_of_name +--------------------------------------------------------------- + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" IS NULL LIMIT ? [["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::MissionTest: test_published_scope_returns_only_published_missions +------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? AND "break_escape_missions"."id" = ? LIMIT ? [["published", 1], ["id", 418560898], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 636030761], ["LIMIT", 1]] + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? AND "break_escape_missions"."id" = ? LIMIT ? [["published", 1], ["id", 636030761], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------- +BreakEscape::MissionTest: test_should_validate_uniqueness_of_name +----------------------------------------------------------------- + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Exists? (0.1ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" = ? LIMIT ? [["name", "test"], ["LIMIT", 1]] + BreakEscape::Mission Create (0.0ms) INSERT INTO "break_escape_missions" ("name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at", "secgen_scenario", "collection") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["name", "test"], ["display_name", "Test"], ["description", nil], ["published", 0], ["difficulty_level", 1], ["created_at", "2025-11-25 16:25:19.364847"], ["updated_at", "2025-11-25 16:25:19.364847"], ["secgen_scenario", nil], ["collection", "default"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" = ? LIMIT ? [["name", "test"], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------- +BreakEscape::MissionTest: test_scenario_path_returns_correct_path +----------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::RoomLazyLoadTest: test_should_return_404_for_non-existent_room +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.366392"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.366359"], ["updated_at", "2025-11-25 16:25:19.366359"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/room/non_existent_room" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#room as HTML + Parameters: {"id"=>"1", "room_id"=>"non_existent_room"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------ +BreakEscape::RoomLazyLoadTest: test_room_response_includes_all_room_data +------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.368520"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.368489"], ["updated_at", "2025-11-25 16:25:19.368489"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/room/test_room" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#room as HTML + Parameters: {"id"=>"1", "room_id"=>"test_room"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Serving room data for: test_room +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::RoomLazyLoadTest: test_should_return_room_data_for_valid_room_id +----------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.370733"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.370699"], ["updated_at", "2025-11-25 16:25:19.370699"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/room/test_room" for 127.0.0.1 at 2025-11-25 16:25:19 +0000 +Processing by BreakEscape::GamesController#room as HTML + Parameters: {"id"=>"1", "room_id"=>"test_room"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Serving room data for: test_room +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::RoomLazyLoadTest: test_should_return_400_when_room_id_is_missing +----------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:19.372867"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:19.372836"], ["updated_at", "2025-11-25 16:25:19.372836"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + ActiveRecord::InternalMetadata Load (0.1ms) 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.0ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC + TRANSACTION (0.0ms) begin transaction +  (0.1ms) PRAGMA foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys = ON +  (0.0ms) PRAGMA foreign_keys = OFF + Fixtures Load (0.1ms) 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-25 16:25:37', '2025-11-25 16:25:37'); +INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-25 16:25:37', '2025-11-25 16:25:37'); +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-25 16:25:37', '2025-11-25 16:25:37'); +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-25 16:25:37', '2025-11-25 16:25:37') +  (0.0ms) PRAGMA defer_foreign_keys = 0 +  (0.0ms) PRAGMA foreign_keys = 1 + TRANSACTION (1.0ms) commit transaction +  (0.0ms) PRAGMA foreign_key_check + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_sync_state_should_update_player_state_for_current_room +--------------------------------------------------------------------------------------------- + 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:37.971182"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:37.971097"], ["updated_at", "2025-11-25 16:25:37.971097"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-25 16:25:37 +0000 +Processing by BreakEscape::GamesController#sync_state as HTML + Parameters: {"currentRoom"=>"reception", "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.0ms) 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.0ms) 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::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + ActiveRecord::InternalMetadata Load (0.1ms) 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.0ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC + TRANSACTION (0.0ms) begin transaction +  (0.1ms) PRAGMA foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys = ON +  (0.0ms) PRAGMA foreign_keys = OFF + Fixtures Load (0.1ms) 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-25 16:25:43', '2025-11-25 16:25:43'); +INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-25 16:25:43', '2025-11-25 16:25:43'); +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-25 16:25:43', '2025-11-25 16:25:43'); +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-25 16:25:43', '2025-11-25 16:25:43') +  (0.0ms) PRAGMA defer_foreign_keys = 0 +  (0.0ms) PRAGMA foreign_keys = 1 + TRANSACTION (0.9ms) commit transaction +  (0.0ms) PRAGMA foreign_key_check + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_unlock_endpoint_should_reject_invalid_attempts +------------------------------------------------------------------------------------- + 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:43.222891"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:43.222755"], ["updated_at", "2025-11-25 16:25:43.222755"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:43 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"room", "targetId"=>"office", "attempt"=>"wrong_code", "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.0ms) 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.0ms) 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=room, id=office, attempt=wrong_code, method=pin +[BreakEscape] Object not found: office +Completed 422 Unprocessable Content in 3ms (Views: 0.1ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + ActiveRecord::InternalMetadata Load (0.1ms) 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.0ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC + TRANSACTION (0.0ms) begin transaction +  (0.1ms) PRAGMA foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys = ON +  (0.0ms) PRAGMA foreign_keys = OFF + Fixtures Load (0.1ms) 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-25 16:25:49', '2025-11-25 16:25:49'); +INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-25 16:25:49', '2025-11-25 16:25:49'); +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-25 16:25:49', '2025-11-25 16:25:49'); +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-25 16:25:49', '2025-11-25 16:25:49') +  (0.0ms) PRAGMA defer_foreign_keys = 0 +  (0.0ms) PRAGMA foreign_keys = 1 + TRANSACTION (1.4ms) commit transaction +  (0.0ms) PRAGMA foreign_key_check + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------- +BreakEscape::MissionTest: test_scenario_path_returns_correct_path +----------------------------------------------------------------- + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------- +BreakEscape::MissionTest: test_should_validate_uniqueness_of_name +----------------------------------------------------------------- + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Exists? (0.1ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" = ? LIMIT ? [["name", "test"], ["LIMIT", 1]] + BreakEscape::Mission Create (0.1ms) INSERT INTO "break_escape_missions" ("name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at", "secgen_scenario", "collection") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["name", "test"], ["display_name", "Test"], ["description", nil], ["published", 0], ["difficulty_level", 1], ["created_at", "2025-11-25 16:25:49.328170"], ["updated_at", "2025-11-25 16:25:49.328170"], ["secgen_scenario", nil], ["collection", "default"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" = ? LIMIT ? [["name", "test"], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------- +BreakEscape::MissionTest: test_should_validate_presence_of_name +--------------------------------------------------------------- + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" IS NULL LIMIT ? [["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::MissionTest: test_published_scope_returns_only_published_missions +------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? AND "break_escape_missions"."id" = ? LIMIT ? [["published", 1], ["id", 418560898], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 636030761], ["LIMIT", 1]] + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? AND "break_escape_missions"."id" = ? LIMIT ? [["published", 1], ["id", 636030761], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_locked_door_cannot_be_bypassed_with_method='unlocked' +--------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.2ms) 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-25 16:25:49.353785"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.353676"], ["updated_at", "2025-11-25 16:25:49.353676"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +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.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: unlocked +[BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED door: office_pin +Completed 422 Unprocessable Content in 3ms (Views: 0.1ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) 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.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.367236"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.367164"], ["updated_at", "2025-11-25 16:25:49.367164"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:25:49.367854"], ["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-25 16:25:49 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlock_non-existent_object_should_fail +-------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.370329"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.370258"], ["updated_at", "2025-11-25 16:25:49.370258"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_biometric_lock:_should_trust_client_validation +------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.2ms) 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-25 16:25:49.372483"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.372419"], ["updated_at", "2025-11-25 16:25:49.372419"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"scanner_biometric", "attempt"=>nil, "method"=>"biometric", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:49.374533"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 2ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlocked_container:_should_grant_access_without_validation +---------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.375796"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.375732"], ["updated_at", "2025-11-25 16:25:49.375732"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:49.377500"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_NPC_unlock_adds_door_to_unlockedRooms +------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.378941"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.378877"], ["updated_at", "2025-11-25 16:25:49.378877"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:25:49.379504"], ["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-25 16:25:49 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin +[BreakEscape] NPC unlock validated: helper_npc can unlock office_pin + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:49.381159"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlock_same_door_twice_should_be_idempotent +------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.382583"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.382517"], ["updated_at", "2025-11-25 16:25:49.382517"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:49.384260"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_incorrect_PIN_should_fail +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.387052"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.386990"], ["updated_at", "2025-11-25 16:25:49.386990"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_player_has_not_encountered_NPC +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.389217"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.389153"], ["updated_at", "2025-11-25 16:25:49.389153"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:25:49.389877"], ["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-25 16:25:49 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin +[BreakEscape] Player has not encountered NPC: helper_npc +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_locked_container_cannot_be_bypassed_with_method='unlocked' +-------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.392289"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.392222"], ["updated_at", "2025-11-25 16:25:49.392222"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_NPC_can_unlock_door_if_player_has_encountered_them_and_NPC_has_permission +------------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.394690"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.394619"], ["updated_at", "2025-11-25 16:25:49.394619"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:25:49.395257"], ["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-25 16:25:49 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin +[BreakEscape] NPC unlock validated: helper_npc can unlock office_pin + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:49.396863"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_password_lock:_incorrect_password_should_fail +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.398290"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.398227"], ["updated_at", "2025-11-25 16:25:49.398227"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"wrongpassword", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: false +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_key_lock:_should_trust_client_validation +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.400605"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.400535"], ["updated_at", "2025-11-25 16:25:49.400535"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_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\":[],\"inventory\":[{\"id\":\"office_key\",\"type\":\"key\",\"name\":\"Office Key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:25:49.401158"], ["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-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=key, requires=office_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=, is_match=true +[BreakEscape] Key office_key found in inventory: true +[BreakEscape] Key validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_key\"],\"unlockedObjects\":[],\"inventory\":[{\"id\":\"office_key\",\"type\":\"key\",\"name\":\"Office Key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:25:49.402681"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_incorrect_PIN_should_fail +--------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.404053"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.403992"], ["updated_at", "2025-11-25 16:25:49.403992"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: false +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_RFID_lock:_should_trust_client_validation +-------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.409088"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.409000"], ["updated_at", "2025-11-25 16:25:49.409000"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"door_rfid", "attempt"=>nil, "method"=>"rfid", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:49.410962"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.2ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_already-unlocked_door_accepts_method='unlocked' +----------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.412378"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.412307"], ["updated_at", "2025-11-25 16:25:49.412307"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:25:49.412968"], ["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-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"ceo", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=password, requires=TopSecret123 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=ceo +[BreakEscape] NPC unlock validated: helper_npc can unlock ceo + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:49.414784"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"ceo", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_correct_PIN_should_unlock +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.2ms) 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-25 16:25:49.417498"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.417432"], ["updated_at", "2025-11-25 16:25:49.417432"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:49.419237"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_password_lock:_empty_attempt_should_fail +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.420693"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.420633"], ["updated_at", "2025-11-25 16:25:49.420633"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_multiple_unlock_attempts_should_update_state_correctly +------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.422919"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.422857"], ["updated_at", "2025-11-25 16:25:49.422857"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:49.424748"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:49.426492"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:49.428251"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_unlockable_is_not_an_array +-------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.429899"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.429830"], ["updated_at", "2025-11-25 16:25:49.429830"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:25:49.430458"], ["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-25 16:25:49 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_already-unlocked_container_accepts_method='unlocked' +---------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.432678"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.432615"], ["updated_at", "2025-11-25 16:25:49.432615"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:25:49.433203"], ["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-25 16:25:49 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:49.434759"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"npc_safe", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_containers +----------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.437443"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.437381"], ["updated_at", "2025-11-25 16:25:49.437381"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:49.439072"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_unlock_response_should_filter_requires_from_contents +-------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.440506"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.440426"], ["updated_at", "2025-11-25 16:25:49.440426"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:49.442167"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_lockpick:_should_trust_client_validation +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.443422"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.443361"], ["updated_at", "2025-11-25 16:25:49.443361"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"box_lockpick", "attempt"=>nil, "method"=>"lockpick", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:49.445057"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_password_lock:_case_sensitivity +----------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.447305"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.447232"], ["updated_at", "2025-11-25 16:25:49.447232"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"OpenSesame", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.4ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: false +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 2ms (Views: 0.0ms | ActiveRecord: 0.5ms (3 queries, 0 cached) | GC: 0.9ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlock_with_invalid_method_should_fail +-------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.453904"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.453433"], ["updated_at", "2025-11-25 16:25:49.453433"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.5ms) 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 +[BreakEscape] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: invalid_method +[BreakEscape] SECURITY VIOLATION: No valid unlock method for LOCKED door: office_pin, method=invalid_method +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 2ms (Views: 0.0ms | ActiveRecord: 0.5ms (3 queries, 0 cached) | GC: 0.9ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlocked_door:_should_grant_access_without_validation +----------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.5ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.460832"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.460760"], ["updated_at", "2025-11-25 16:25:49.460760"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.5ms) 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] Room data: locked=false, lockType=, requires= +[BreakEscape] Door is unlocked in scenario data, granting access + TRANSACTION (0.0ms) 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\",\"office_unlocked\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:25:49.466002"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 5ms (Views: 0.5ms | ActiveRecord: 0.7ms (5 queries, 0 cached) | GC: 3.2ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) 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.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.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-25 16:25:49.470503"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.470439"], ["updated_at", "2025-11-25 16:25:49.470439"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:25:49.472257"], ["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-25 16:25:49 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) 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-25 16:25:49.477669"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 3ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 1.2ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_container_with_password_lock:_correct_password_should_unlock +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.479688"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.479591"], ["updated_at", "2025-11-25 16:25:49.479591"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"secret123", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:49.481863"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 2ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.2ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_unlock_response_should_not_expose_'requires'_field_for_exploitable_locks +----------------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.483541"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.483476"], ["updated_at", "2025-11-25 16:25:49.483476"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:49.485322"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_bluetooth_lock:_should_trust_client_validation +------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.486584"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.486511"], ["updated_at", "2025-11-25 16:25:49.486511"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"terminal_bluetooth", "attempt"=>nil, "method"=>"bluetooth", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:49.488227"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_password_lock:_correct_password_should_unlock +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.489426"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.489289"], ["updated_at", "2025-11-25 16:25:49.489289"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:49.491162"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_key_lock:_should_trust_client_validation +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.492741"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.492672"], ["updated_at", "2025-11-25 16:25:49.492672"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"drawer_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:49.494503"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_unlock_non-existent_door_should_fail +------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.495811"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.495751"], ["updated_at", "2025-11-25 16:25:49.495751"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_doors +------------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.498037"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.497974"], ["updated_at", "2025-11-25 16:25:49.497974"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=false, lockType=, requires= +[BreakEscape] Door is unlocked in scenario data, granting access + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:49.499754"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_for_non-existent_NPC +----------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.500980"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.500920"], ["updated_at", "2025-11-25 16:25:49.500920"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_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\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:25:49.501476"], ["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-25 16:25:49 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=fake_npc, target=office_pin +[BreakEscape] NPC not found: fake_npc +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_correct_PIN_should_unlock +--------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:25:49.503471"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.503409"], ["updated_at", "2025-11-25 16:25:49.503409"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:25:49.505120"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------- +BreakEscapeTest: test_it_has_a_version_number +--------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_CSS:_should_return_404_for_non-existent_files +------------------------------------------------------------------------------------------ +Started GET "/break_escape/css/non-existent.css" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"non-existent.css"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 1ms (Views: 1.4ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_CSS_files_are_non-empty +------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.1ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Minigame:_should_serve_lockpicking_script +-------------------------------------------------------------------------------------- +Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/lockpicking-game-phaser.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_audio_files_are_non-empty +--------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_image_files_are_non-empty +--------------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_JS:_should_serve_core_game_module +------------------------------------------------------------------------------ +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Routes:_should_handle_files_with_multiple_dots +------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door_sheet_32.png" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_sheet_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_sheet_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Routes:_should_capture_full_filename_with_extension +------------------------------------------------------------------------------------------------ +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Assets:_should_serve_PNG_tiles_with_correct_MIME_type +-------------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Routes:_should_capture_complex_paths_with_segments +----------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_HTML:_should_return_404_for_non-existent_files +------------------------------------------------------------------------------------------- +Started GET "/break_escape/non-existent.html" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 + +ActionController::RoutingError (No route matches [GET] "/break_escape/non-existent.html"): + + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_JS:_should_return_404_for_non-existent_files +----------------------------------------------------------------------------------------- +Started GET "/break_escape/js/non-existent.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"non-existent.js"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_HTML:_should_serve_test_files_with_correct_MIME_type +------------------------------------------------------------------------------------------------- +Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as HTML + Parameters: {"filename"=>"test-assets"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/test-assets.html (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_CSS:_should_serve_files_with_correct_MIME_type +------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Assets:_should_serve_audio_with_correct_MIME_type +---------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_CSS:_should_serve_with_inline_disposition +-------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Headers:_should_set_Content-Disposition_to_inline +---------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Headers:_should_include_Cache-Control +---------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_JavaScript_files_are_non-empty +-------------------------------------------------------------------------------------- +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Phaser:_constants_define_GAME_CONFIG_with_baseURL +---------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Security:_should_prevent_directory_traversal_in_CSS +------------------------------------------------------------------------------------------------ +Started GET "/break_escape/css/../../config/database.yml" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/database.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Assets:_should_return_404_for_non-existent_files +--------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/non-existent.mp3" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/non-existent.mp3"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Minigame:_should_serve_lockpicking_sounds +-------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_click.mp3" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_click.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_click.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_success.mp3" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_success.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_success.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Phaser:_game.js_has_asset_references_without_prefix +------------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_JS:_should_serve_files_with_correct_MIME_type +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_JS:_should_serve_nested_files +-------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Security:_should_prevent_directory_traversal_in_JS +----------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/../../config/secrets.yml" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/secrets.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Security:_should_prevent_directory_traversal_in_assets +--------------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/../../config/database.yml" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/database.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Headers:_should_include_Content-Length +----------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Assets:_should_serve_nested_files +------------------------------------------------------------------------------ +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Phaser:_main_JS_imports_GAME_CONFIG +-------------------------------------------------------------------------------- +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_preserves_lock_requirements +--------------------------------------------------------------------------------------------------- + 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.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.575207"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.575140"], ["updated_at", "2025-11-25 16:25:49.575140"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_removes_room_contents +--------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.576535"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.576486"], ["updated_at", "2025-11-25 16:25:49.576486"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------------ +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_preserves_navigation_structure +------------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.577557"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.577517"], ["updated_at", "2025-11-25 16:25:49.577517"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_removes_objects_and_npcs +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.578650"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.578608"], ["updated_at", "2025-11-25 16:25:49.578608"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_does_not_modify_original +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.579725"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.579681"], ["updated_at", "2025-11-25 16:25:49.579681"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------ +BreakEscape::MissionsControllerTest: test_index_should_return_HTML_with_mission_list +------------------------------------------------------------------------------------ +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.0ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" = ? [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.2ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 5.5ms | GC: 0.1ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 5.6ms | GC: 0.1ms) +Completed 200 OK in 6ms (Views: 5.6ms | ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_show_published_mission +----------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] +Started GET "/break_escape/missions/418560898" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::MissionsController#show as HTML + Parameters: {"id"=>"418560898"} + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."player_type" = ? AND "break_escape_games"."player_id" = ? AND "break_escape_games"."mission_id" = ? LIMIT ? [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) 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", "{\"scenario_brief\":\"Hi! You are a cyber investigator tasked with uncovering evidence of corporate espionage. Anonymous tips suggest the CEO has been selling company secrets, but you need proof.\",\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office1\"},\"npcs\":[{\"id\":\"neye_eve\",\"displayName\":\"Neye Eve\",\"storyPath\":\"scenarios/ink/neye-eve.json\",\"avatar\":\"assets/npc/avatars/npc_adversary.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\"},{\"id\":\"gossip_girl\",\"displayName\":\"Gossip Girl\",\"storyPath\":\"scenarios/ink/gossip-girl.json\",\"avatar\":\"assets/npc/avatars/npc_neutral.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"timedMessages\":[{\"delay\":5000,\"message\":\"Hey! 👋 Got any juicy gossip for me today?\",\"type\":\"text\"}]},{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"storyPath\":\"scenarios/ink/helper-npc.json\",\"avatar\":\"assets/npc/avatars/npc_helper.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"unlockable\":[\"secure_vault\",\"ceo\"],\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":15000},{\"eventPattern\":\"door_unlocked\",\"targetKnot\":\"on_door_unlocked\",\"cooldown\":8000},{\"eventPattern\":\"door_unlock_attempt\",\"targetKnot\":\"on_door_attempt\",\"cooldown\":12000},{\"eventPattern\":\"object_interacted\",\"targetKnot\":\"on_ceo_desk_interact\",\"condition\":\"data.objectType === 'desk_ceo'\",\"cooldown\":10000},{\"eventPattern\":\"item_picked_up:*\",\"targetKnot\":\"on_item_found\",\"cooldown\":20000},{\"eventPattern\":\"room_entered\",\"targetKnot\":\"on_room_entered\",\"cooldown\":45000,\"maxTriggers\":3},{\"eventPattern\":\"room_discovered\",\"targetKnot\":\"on_room_discovered\",\"cooldown\":15000,\"maxTriggers\":5},{\"eventPattern\":\"room_entered:ceo\",\"targetKnot\":\"on_ceo_office_entered\",\"onceOnly\":true}]}],\"objects\":[{\"type\":\"phone\",\"name\":\"Reception Phone\",\"takeable\":false,\"readable\":true,\"voice\":\"Hi, this is the IT Team. Security breach detected in server room. Changed access code to 4829.\",\"sender\":\"IT Team\",\"timestamp\":\"2:15 AM\",\"observations\":\"The reception phone's message light is blinking urgently\"},{\"type\":\"notes\",\"name\":\"Security Log\",\"takeable\":true,\"readable\":true,\"text\":\"Unusual after-hours access detected:\\n- CEO office: 11:30 PM\\n- Server room: 2:15 AM\\n- CEO office again: 3:45 AM\",\"observations\":\"A concerning security log from last night\"},{\"type\":\"pc\",\"name\":\"Reception Computer\",\"takeable\":false,\"lockType\":\"password\",\"passwordHint\":\"Optional hint text\",\"showHint\":true,\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"requires\":\"secret123\",\"observations\":\"The reception's computer, currently locked\",\"postitNote\":\"Password: secret123\",\"showPostit\":true,\"contents\":[{\"type\":\"text_file\",\"name\":\"Private\",\"takeable\":false,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\"}]},{\"type\":\"tablet\",\"name\":\"Tablet Device\",\"takeable\":true,\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"A locked tablet device that requires Bluetooth pairing\"},{\"type\":\"bluetooth_scanner\",\"name\":\"Bluetooth Scanner\",\"takeable\":true,\"observations\":\"A device for detecting nearby Bluetooth signals\",\"canScanBluetooth\":true},{\"type\":\"key\",\"name\":\"Office Key\",\"takeable\":true,\"key_id\":\"office1_key\",\"keyPins\":[65,25,65,25],\"observations\":\"A key to access the office areas\"},{\"type\":\"pin-cracker\",\"name\":\"PIN Cracker\",\"takeable\":true,\"observations\":\"A sophisticated device that can analyze PIN entry patterns and provide feedback on attempts\"},{\"type\":\"safe\",\"name\":\"Reception Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9573\",\"observations\":\"A small wall safe behind the reception desk. Looks like it needs a 4-digit code.\",\"contents\":[{\"type\":\"notes\",\"name\":\"IT Access Credentials\",\"takeable\":true,\"readable\":true,\"text\":\"Emergency IT Admin Credentials:\\nUsername: admin\\nPassword: ITsecure2024\\n\\nServer Room Backup Code: 4829\\nCEO Office Alarm Override: 1337\",\"observations\":\"Sensitive IT credentials that could be very useful\"}]}]},\"office1\":{\"type\":\"room_office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office1_key\",\"keyPins\":[65,25,65,25],\"difficulty\":\"easy\",\"door_sign\":\"4A Hot Desks\",\"connections\":{\"north\":[\"office2\",\"office3\"],\"south\":\"reception\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"requires\":\"password\",\"hasFingerprint\":true,\"fingerprintOwner\":\"ceo\",\"fingerprintDifficulty\":\"medium\",\"observations\":\"A computer with a cybersecurity alert on screen. There might be fingerprints on the keyboard.\"},{\"type\":\"notes\",\"name\":\"IT Memo\",\"takeable\":true,\"readable\":true,\"text\":\"URGENT: Multiple unauthorized access attempts detected from CEO's office IP address\",\"observations\":\"A concerning IT department memo\"},{\"type\":\"fingerprint_kit\",\"name\":\"Fingerprint Kit\",\"takeable\":true,\"observations\":\"A kit used for collecting fingerprints from surfaces\"}]},\"office2\":{\"type\":\"room_office\",\"connections\":{\"north\":\"ceo\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"office2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: office2024\",\"showPostit\":true,\"observations\":\"A standard office computer with a sticky note on the monitor\"},{\"type\":\"notes\",\"name\":\"Shredded Document\",\"takeable\":true,\"readable\":true,\"text\":\"Partially readable: '...offshore account...transfer complete...delete all traces...'\",\"observations\":\"A partially shredded document that someone failed to dispose of properly\"},{\"type\":\"key\",\"name\":\"CEO Office Key\",\"takeable\":true,\"key_id\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"observations\":\"A spare key to the CEO's office, carelessly left behind\"}]},\"office3\":{\"type\":\"room_office\",\"connections\":{\"north\":\"server1\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"IT Staff Computer\",\"takeable\":false,\"requires\":\"bluetooth\",\"lockType\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"An IT staff computer showing network security logs\"},{\"type\":\"notes\",\"name\":\"Network Logs\",\"takeable\":true,\"readable\":true,\"text\":\"Large data transfers detected to unknown external IPs - All originating from CEO's office\",\"observations\":\"Suspicious network activity logs\"}]},\"ceo\":{\"type\":\"room_ceo\",\"connections\":{\"north\":\"closet\",\"south\":\"office2\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"difficulty\":\"easy\",\"objects\":[{\"type\":\"pc\",\"name\":\"CEO Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"ceo2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: ceo2024\",\"showPostit\":true,\"observations\":\"The CEO's laptop, still warm - recently used. A sticky note is attached to the screen.\"},{\"type\":\"suitcase\",\"name\":\"CEO Briefcase\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"difficulty\":\"medium\",\"observations\":\"An expensive leather briefcase with a sturdy lock\",\"contents\":[{\"type\":\"notes\",\"name\":\"Private Note\",\"takeable\":true,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\",\"observations\":\"A hastily written note on expensive paper\"},{\"type\":\"key\",\"name\":\"Safe Key\",\"takeable\":true,\"key_id\":\"safe_key\",\"keyPins\":[52,29,44,37],\"observations\":\"A heavy-duty safe key hidden behind server equipment\"}]},{\"type\":\"phone\",\"name\":\"CEO Phone\",\"takeable\":false,\"readable\":true,\"text\":\"Recent calls: 'Offshore Bank', 'Unknown', 'Data Buyer'\",\"sender\":\"Call Log\",\"timestamp\":\"Last 24 hours\",\"observations\":\"The CEO's phone shows suspicious recent calls\"}]},\"closet\":{\"type\":\"room_closet\",\"connections\":{\"south\":\"ceo\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"7391\",\"objects\":[{\"type\":\"safe\",\"name\":\"Hidden Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"safe_key\",\"keyPins\":[52,29,44,37],\"difficulty\":\"hard\",\"observations\":\"A well-hidden wall safe behind a painting\",\"contents\":[{\"type\":\"notes\",\"name\":\"Incriminating Documents\",\"takeable\":true,\"readable\":true,\"text\":\"Contract for sale of proprietary technology\\nBank transfers from competing companies\\nDetails of upcoming corporate espionage operations\",\"observations\":\"A folder containing damning evidence of corporate espionage. Congratulations! You've recovered the incriminating documents. flag{ceo_exfil_flag}\"}]}]},\"server1\":{\"type\":\"room_servers\",\"connections\":{\"south\":\"office3\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"4829\",\"objects\":[{\"type\":\"pc\",\"name\":\"Server Terminal\",\"takeable\":false,\"observations\":\"The main server terminal showing massive data exfiltration\"},{\"type\":\"key\",\"name\":\"Briefcase Key\",\"takeable\":true,\"key_id\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.590851"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.590175"], ["updated_at", "2025-11-25 16:25:49.590175"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Redirected to http://www.example.com/break_escape/games/1 +Completed 302 Found in 2ms (ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_create_game_and_redirect_when_showing_mission +---------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Count (0.0ms) SELECT COUNT(*) FROM "break_escape_games" +Started GET "/break_escape/missions/418560898" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::MissionsController#show as HTML + Parameters: {"id"=>"418560898"} + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."player_type" = ? AND "break_escape_games"."player_id" = ? AND "break_escape_games"."mission_id" = ? LIMIT ? [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) 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", "{\"scenario_brief\":\"Hi! You are a cyber investigator tasked with uncovering evidence of corporate espionage. Anonymous tips suggest the CEO has been selling company secrets, but you need proof.\",\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office1\"},\"npcs\":[{\"id\":\"neye_eve\",\"displayName\":\"Neye Eve\",\"storyPath\":\"scenarios/ink/neye-eve.json\",\"avatar\":\"assets/npc/avatars/npc_adversary.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\"},{\"id\":\"gossip_girl\",\"displayName\":\"Gossip Girl\",\"storyPath\":\"scenarios/ink/gossip-girl.json\",\"avatar\":\"assets/npc/avatars/npc_neutral.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"timedMessages\":[{\"delay\":5000,\"message\":\"Hey! 👋 Got any juicy gossip for me today?\",\"type\":\"text\"}]},{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"storyPath\":\"scenarios/ink/helper-npc.json\",\"avatar\":\"assets/npc/avatars/npc_helper.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"unlockable\":[\"secure_vault\",\"ceo\"],\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":15000},{\"eventPattern\":\"door_unlocked\",\"targetKnot\":\"on_door_unlocked\",\"cooldown\":8000},{\"eventPattern\":\"door_unlock_attempt\",\"targetKnot\":\"on_door_attempt\",\"cooldown\":12000},{\"eventPattern\":\"object_interacted\",\"targetKnot\":\"on_ceo_desk_interact\",\"condition\":\"data.objectType === 'desk_ceo'\",\"cooldown\":10000},{\"eventPattern\":\"item_picked_up:*\",\"targetKnot\":\"on_item_found\",\"cooldown\":20000},{\"eventPattern\":\"room_entered\",\"targetKnot\":\"on_room_entered\",\"cooldown\":45000,\"maxTriggers\":3},{\"eventPattern\":\"room_discovered\",\"targetKnot\":\"on_room_discovered\",\"cooldown\":15000,\"maxTriggers\":5},{\"eventPattern\":\"room_entered:ceo\",\"targetKnot\":\"on_ceo_office_entered\",\"onceOnly\":true}]}],\"objects\":[{\"type\":\"phone\",\"name\":\"Reception Phone\",\"takeable\":false,\"readable\":true,\"voice\":\"Hi, this is the IT Team. Security breach detected in server room. Changed access code to 4829.\",\"sender\":\"IT Team\",\"timestamp\":\"2:15 AM\",\"observations\":\"The reception phone's message light is blinking urgently\"},{\"type\":\"notes\",\"name\":\"Security Log\",\"takeable\":true,\"readable\":true,\"text\":\"Unusual after-hours access detected:\\n- CEO office: 11:30 PM\\n- Server room: 2:15 AM\\n- CEO office again: 3:45 AM\",\"observations\":\"A concerning security log from last night\"},{\"type\":\"pc\",\"name\":\"Reception Computer\",\"takeable\":false,\"lockType\":\"password\",\"passwordHint\":\"Optional hint text\",\"showHint\":true,\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"requires\":\"secret123\",\"observations\":\"The reception's computer, currently locked\",\"postitNote\":\"Password: secret123\",\"showPostit\":true,\"contents\":[{\"type\":\"text_file\",\"name\":\"Private\",\"takeable\":false,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\"}]},{\"type\":\"tablet\",\"name\":\"Tablet Device\",\"takeable\":true,\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"A locked tablet device that requires Bluetooth pairing\"},{\"type\":\"bluetooth_scanner\",\"name\":\"Bluetooth Scanner\",\"takeable\":true,\"observations\":\"A device for detecting nearby Bluetooth signals\",\"canScanBluetooth\":true},{\"type\":\"key\",\"name\":\"Office Key\",\"takeable\":true,\"key_id\":\"office1_key\",\"keyPins\":[65,25,65,25],\"observations\":\"A key to access the office areas\"},{\"type\":\"pin-cracker\",\"name\":\"PIN Cracker\",\"takeable\":true,\"observations\":\"A sophisticated device that can analyze PIN entry patterns and provide feedback on attempts\"},{\"type\":\"safe\",\"name\":\"Reception Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9573\",\"observations\":\"A small wall safe behind the reception desk. Looks like it needs a 4-digit code.\",\"contents\":[{\"type\":\"notes\",\"name\":\"IT Access Credentials\",\"takeable\":true,\"readable\":true,\"text\":\"Emergency IT Admin Credentials:\\nUsername: admin\\nPassword: ITsecure2024\\n\\nServer Room Backup Code: 4829\\nCEO Office Alarm Override: 1337\",\"observations\":\"Sensitive IT credentials that could be very useful\"}]}]},\"office1\":{\"type\":\"room_office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office1_key\",\"keyPins\":[65,25,65,25],\"difficulty\":\"easy\",\"door_sign\":\"4A Hot Desks\",\"connections\":{\"north\":[\"office2\",\"office3\"],\"south\":\"reception\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"requires\":\"password\",\"hasFingerprint\":true,\"fingerprintOwner\":\"ceo\",\"fingerprintDifficulty\":\"medium\",\"observations\":\"A computer with a cybersecurity alert on screen. There might be fingerprints on the keyboard.\"},{\"type\":\"notes\",\"name\":\"IT Memo\",\"takeable\":true,\"readable\":true,\"text\":\"URGENT: Multiple unauthorized access attempts detected from CEO's office IP address\",\"observations\":\"A concerning IT department memo\"},{\"type\":\"fingerprint_kit\",\"name\":\"Fingerprint Kit\",\"takeable\":true,\"observations\":\"A kit used for collecting fingerprints from surfaces\"}]},\"office2\":{\"type\":\"room_office\",\"connections\":{\"north\":\"ceo\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"office2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: office2024\",\"showPostit\":true,\"observations\":\"A standard office computer with a sticky note on the monitor\"},{\"type\":\"notes\",\"name\":\"Shredded Document\",\"takeable\":true,\"readable\":true,\"text\":\"Partially readable: '...offshore account...transfer complete...delete all traces...'\",\"observations\":\"A partially shredded document that someone failed to dispose of properly\"},{\"type\":\"key\",\"name\":\"CEO Office Key\",\"takeable\":true,\"key_id\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"observations\":\"A spare key to the CEO's office, carelessly left behind\"}]},\"office3\":{\"type\":\"room_office\",\"connections\":{\"north\":\"server1\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"IT Staff Computer\",\"takeable\":false,\"requires\":\"bluetooth\",\"lockType\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"An IT staff computer showing network security logs\"},{\"type\":\"notes\",\"name\":\"Network Logs\",\"takeable\":true,\"readable\":true,\"text\":\"Large data transfers detected to unknown external IPs - All originating from CEO's office\",\"observations\":\"Suspicious network activity logs\"}]},\"ceo\":{\"type\":\"room_ceo\",\"connections\":{\"north\":\"closet\",\"south\":\"office2\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"difficulty\":\"easy\",\"objects\":[{\"type\":\"pc\",\"name\":\"CEO Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"ceo2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: ceo2024\",\"showPostit\":true,\"observations\":\"The CEO's laptop, still warm - recently used. A sticky note is attached to the screen.\"},{\"type\":\"suitcase\",\"name\":\"CEO Briefcase\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"difficulty\":\"medium\",\"observations\":\"An expensive leather briefcase with a sturdy lock\",\"contents\":[{\"type\":\"notes\",\"name\":\"Private Note\",\"takeable\":true,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\",\"observations\":\"A hastily written note on expensive paper\"},{\"type\":\"key\",\"name\":\"Safe Key\",\"takeable\":true,\"key_id\":\"safe_key\",\"keyPins\":[52,29,44,37],\"observations\":\"A heavy-duty safe key hidden behind server equipment\"}]},{\"type\":\"phone\",\"name\":\"CEO Phone\",\"takeable\":false,\"readable\":true,\"text\":\"Recent calls: 'Offshore Bank', 'Unknown', 'Data Buyer'\",\"sender\":\"Call Log\",\"timestamp\":\"Last 24 hours\",\"observations\":\"The CEO's phone shows suspicious recent calls\"}]},\"closet\":{\"type\":\"room_closet\",\"connections\":{\"south\":\"ceo\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"7391\",\"objects\":[{\"type\":\"safe\",\"name\":\"Hidden Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"safe_key\",\"keyPins\":[52,29,44,37],\"difficulty\":\"hard\",\"observations\":\"A well-hidden wall safe behind a painting\",\"contents\":[{\"type\":\"notes\",\"name\":\"Incriminating Documents\",\"takeable\":true,\"readable\":true,\"text\":\"Contract for sale of proprietary technology\\nBank transfers from competing companies\\nDetails of upcoming corporate espionage operations\",\"observations\":\"A folder containing damning evidence of corporate espionage. Congratulations! You've recovered the incriminating documents. flag{ceo_exfil_flag}\"}]}]},\"server1\":{\"type\":\"room_servers\",\"connections\":{\"south\":\"office3\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"4829\",\"objects\":[{\"type\":\"pc\",\"name\":\"Server Terminal\",\"takeable\":false,\"observations\":\"The main server terminal showing massive data exfiltration\"},{\"type\":\"key\",\"name\":\"Briefcase Key\",\"takeable\":true,\"key_id\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.593996"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.593406"], ["updated_at", "2025-11-25 16:25:49.593406"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Redirected to http://www.example.com/break_escape/games/1 +Completed 302 Found in 2ms (ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Count (0.0ms) SELECT COUNT(*) FROM "break_escape_games" + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_get_index +---------------------------------------------------------- +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.0ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" = ? [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 0.6ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.6ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.7ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_index_should_display_published_missions +--------------------------------------------------------------------------------- +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.0ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" = ? [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 0.5ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.5ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.6ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_show_should_inject_game_configuration +---------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.599621"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.599579"], ["updated_at", "2025-11-25 16:25:49.599579"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.5ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.5ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.7ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_game_setup_has_correct_scenario_data +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.602939"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.602900"], ["updated_at", "2025-11-25 16:25:49.602900"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_ink_endpoint_should_require_npc_parameter +-------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.603976"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.603941"], ["updated_at", "2025-11-25 16:25:49.603941"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 400 Bad Request in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------- +BreakEscape::GamesControllerTest: test_should_show_game +------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.2ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.606016"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.605979"], ["updated_at", "2025-11-25 16:25:49.605979"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.1ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.2ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.3ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::GamesControllerTest: test_ink_endpoint_should_return_404_for_NPC_without_story_file +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.608769"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.608731"], ["updated_at", "2025-11-25 16:25:49.608731"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=missing-npc" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"missing-npc", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: missing-npc +[BreakEscape] No NPCs found in scenario data +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_inventory_endpoint_should_add_items +-------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.613313"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.613260"], ["updated_at", "2025-11-25 16:25:49.613260"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[{\"id\":\"note_1\",\"type\":\"note\",\"name\":\"Test Note\",\"takeable\":true}]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:25:49.613871"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/inventory" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#inventory as HTML + Parameters: {"action_type"=>"add", "item"=>{"type"=>"note", "name"=>"Test Note", "id"=>"note_1"}, "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] inventory endpoint: action=add, item=#"note", "name"=>"Test Note", "id"=>"note_1"} permitted: false> +[BreakEscape] validate_item_collectible: type=note, id=note_1, name=Test Note +[BreakEscape] Item collection valid: note +[BreakEscape] Adding item to inventory: note / Test Note + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"note\",\"name\":\"Test Note\",\"id\":\"note_1\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:25:49.615789"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Item added successfully. Current inventory: [{"type"=>"note", "name"=>"Test Note", "id"=>"note_1"}] +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_sync_state_should_update_player_state_for_current_room +--------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.617442"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.617403"], ["updated_at", "2025-11-25 16:25:49.617403"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#sync_state as HTML + Parameters: {"currentRoom"=>"reception", "id"=>"1"} + BreakEscape::Game Load (0.0ms) 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.0ms) 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::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.2ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_scenario_endpoint_should_return_JSON +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.2ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.620387"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.620349"], ["updated_at", "2025-11-25 16:25:49.620349"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#scenario as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_unlock_endpoint_should_accept_correct_pin_code +------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.622952"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.622912"], ["updated_at", "2025-11-25 16:25:49.622912"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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, attempt=1234, method=pin +[BreakEscape] Room data: locked=true, lockType=pin, requires=1234 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\",\"office\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:25:49.624685"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_unlock_endpoint_should_reject_invalid_attempts +------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.625990"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.625954"], ["updated_at", "2025-11-25 16:25:49.625954"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"room", "targetId"=>"office", "attempt"=>"wrong_code", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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=room, id=office, attempt=wrong_code, method=pin +[BreakEscape] Object not found: office +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::GamesControllerTest: test_ink_endpoint_should_return_404_for_non-existent_NPC +------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.628306"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.628259"], ["updated_at", "2025-11-25 16:25:49.628259"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=non-existent" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"non-existent", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: non-existent +[BreakEscape] No NPCs found in scenario data +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_show_should_return_HTML_with_game_container +---------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.630558"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.630520"], ["updated_at", "2025-11-25 16:25:49.630520"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.2ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.2ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.3ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_phone-chat-minigame_should_use_Rails_API_endpoint_for_story_loading +-------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.633897"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.633864"], ["updated_at", "2025-11-25 16:25:49.633864"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/phone-chat/phone-chat-minigame.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/phone-chat/phone-chat-minigame.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/phone-chat/phone-chat-minigame.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_ink_endpoint_should_return_application/json_content_type +--------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.635727"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.635687"], ["updated_at", "2025-11-25 16:25:49.635687"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=security_guard" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"security_guard", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: security_guard +[BreakEscape] Found NPC: security_guard with storyPath: scenarios/ink/security-guard.json +[BreakEscape] Serving ink from: /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/scenarios/ink/security-guard.json +Completed 200 OK in 1ms (Views: 0.3ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_ink_endpoint_should_work_with_underscored_NPC_IDs +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.638275"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.638243"], ["updated_at", "2025-11-25 16:25:49.638243"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=npc-with-underscores" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"npc-with-underscores", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: npc-with-underscores +[BreakEscape] Available NPCs: security_guard (test_room), test-npc (test_room) +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::NPCInkLoadingTest: test_person-chat-portraits_should_import_ASSETS_PATH_from_config +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.640524"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.640492"], ["updated_at", "2025-11-25 16:25:49.640492"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/person-chat/person-chat-portraits.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/person-chat/person-chat-portraits.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/person-chat/person-chat-portraits.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------ +BreakEscape::NPCInkLoadingTest: test_npc-barks_should_import_ASSETS_PATH_from_config +------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.642182"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.642150"], ["updated_at", "2025-11-25 16:25:49.642150"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/systems/npc-barks.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/npc-barks.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/npc-barks.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_npc-manager_should_load_stories_via_API_endpoint +------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.643918"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.643882"], ["updated_at", "2025-11-25 16:25:49.643882"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/systems/npc-manager.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/npc-manager.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/npc-manager.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_404_for_NPC_without_story_file +--------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.645663"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.645629"], ["updated_at", "2025-11-25 16:25:49.645629"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=npc-with-no-file" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"npc-with-no-file", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: npc-with-no-file +[BreakEscape] Available NPCs: security_guard (test_room), test-npc (test_room) +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_person-chat-minigame_should_use_Rails_API_endpoint_for_story_loading +--------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.647888"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.647856"], ["updated_at", "2025-11-25 16:25:49.647856"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/person-chat/person-chat-minigame.js?v=10" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"v"=>"10", "path"=>"minigames/person-chat/person-chat-minigame.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/person-chat/person-chat-minigame.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_404_for_non-existent_game +---------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.2ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.649517"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.649485"], ["updated_at", "2025-11-25 16:25:49.649485"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/999999/ink?npc=test-npc" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"test-npc", "id"=>"999999"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 999999], ["LIMIT", 1]] +Completed 404 Not Found in 0ms (ActiveRecord: 0.0ms (1 query, 0 cached) | GC: 0.0ms) + +ActiveRecord::RecordNotFound (Couldn't find BreakEscape::Game with 'id'="999999"): + +activerecord (7.2.3) lib/active_record/core.rb:268:in `find' +/home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/controllers/break_escape/games_controller.rb:323:in `set_game' +activesupport (7.2.3) lib/active_support/callbacks.rb:362:in `block in make_lambda' +activesupport (7.2.3) lib/active_support/callbacks.rb:179:in `block in call' +actionpack (7.2.3) lib/abstract_controller/callbacks.rb:34:in `block (2 levels) in ' +activesupport (7.2.3) lib/active_support/callbacks.rb:180:in `call' +activesupport (7.2.3) lib/active_support/callbacks.rb:560:in `block in invoke_before' +activesupport (7.2.3) lib/active_support/callbacks.rb:560:in `each' +activesupport (7.2.3) lib/active_support/callbacks.rb:560:in `invoke_before' +activesupport (7.2.3) lib/active_support/callbacks.rb:119:in `block in run_callbacks' +actiontext (7.2.3) lib/action_text/rendering.rb:25:in `with_renderer' +actiontext (7.2.3) lib/action_text/engine.rb:71:in `block (4 levels) in ' +activesupport (7.2.3) lib/active_support/callbacks.rb:130:in `instance_exec' +activesupport (7.2.3) lib/active_support/callbacks.rb:130:in `block in run_callbacks' +activesupport (7.2.3) lib/active_support/callbacks.rb:141:in `run_callbacks' +actionpack (7.2.3) lib/abstract_controller/callbacks.rb:260:in `process_action' +actionpack (7.2.3) lib/action_controller/metal/rescue.rb:27:in `process_action' +actionpack (7.2.3) lib/action_controller/metal/instrumentation.rb:77:in `block in process_action' +activesupport (7.2.3) lib/active_support/notifications.rb:210:in `block in instrument' +activesupport (7.2.3) lib/active_support/notifications/instrumenter.rb:58:in `instrument' +activesupport (7.2.3) lib/active_support/notifications.rb:210:in `instrument' +actionpack (7.2.3) lib/action_controller/metal/instrumentation.rb:76:in `process_action' +actionpack (7.2.3) lib/action_controller/metal/params_wrapper.rb:259:in `process_action' +activerecord (7.2.3) lib/active_record/railties/controller_runtime.rb:39:in `process_action' +actionpack (7.2.3) lib/abstract_controller/base.rb:152:in `process' +actionview (7.2.3) lib/action_view/rendering.rb:40:in `process' +actionpack (7.2.3) lib/action_controller/metal.rb:252:in `dispatch' +actionpack (7.2.3) lib/action_controller/metal.rb:335:in `dispatch' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:67:in `dispatch' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:50:in `serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:53:in `block in serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:133:in `block in find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `each' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:34:in `serve' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:896:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/static.rb:27:in `call' +railties (7.2.3) lib/rails/engine.rb:535:in `call' +railties (7.2.3) lib/rails/railtie.rb:226:in `public_send' +railties (7.2.3) lib/rails/railtie.rb:226:in `method_missing' +actionpack (7.2.3) lib/action_dispatch/routing/mapper.rb:33:in `block in ' +actionpack (7.2.3) lib/action_dispatch/routing/mapper.rb:62:in `serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:53:in `block in serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:133:in `block in find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `each' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:34:in `serve' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:896:in `call' +rack (3.2.4) lib/rack/tempfile_reaper.rb:20:in `call' +rack (3.2.4) lib/rack/etag.rb:29:in `call' +rack (3.2.4) lib/rack/conditional_get.rb:31:in `call' +rack (3.2.4) lib/rack/head.rb:15:in `call' +actionpack (7.2.3) lib/action_dispatch/http/permissions_policy.rb:38:in `call' +actionpack (7.2.3) lib/action_dispatch/http/content_security_policy.rb:38:in `call' +rack-session (2.1.1) lib/rack/session/abstract/id.rb:274:in `context' +rack-session (2.1.1) lib/rack/session/abstract/id.rb:268:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/cookies.rb:704:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/callbacks.rb:31:in `block in call' +activesupport (7.2.3) lib/active_support/callbacks.rb:101:in `run_callbacks' +actionpack (7.2.3) lib/action_dispatch/middleware/callbacks.rb:30:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/actionable_exceptions.rb:18:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/debug_exceptions.rb:31:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/show_exceptions.rb:32:in `call' +railties (7.2.3) lib/rails/rack/logger.rb:41:in `call_app' +railties (7.2.3) lib/rails/rack/logger.rb:29:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/remote_ip.rb:96:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/request_id.rb:33:in `call' +rack (3.2.4) lib/rack/method_override.rb:28:in `call' +rack (3.2.4) lib/rack/runtime.rb:24:in `call' +activesupport (7.2.3) lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/executor.rb:16:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/static.rb:27:in `call' +rack (3.2.4) lib/rack/sendfile.rb:131:in `call' +railties (7.2.3) lib/rails/engine.rb:535:in `call' +rack-test (2.2.0) lib/rack/test.rb:360:in `process_request' +rack-test (2.2.0) lib/rack/test.rb:153:in `request' +actionpack (7.2.3) lib/action_dispatch/testing/integration.rb:287:in `process' +actionpack (7.2.3) lib/action_dispatch/testing/integration.rb:19:in `get' +actionpack (7.2.3) lib/action_dispatch/testing/integration.rb:378:in `get' +/home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/test/integration/npc_ink_loading_test.rb:155:in `block in ' +minitest (5.26.2) lib/minitest/test.rb:95:in `block (2 levels) in run' +minitest (5.26.2) lib/minitest/test.rb:191:in `capture_exceptions' +minitest (5.26.2) lib/minitest/test.rb:90:in `block in run' +minitest (5.26.2) lib/minitest.rb:383:in `time_it' +minitest (5.26.2) lib/minitest/test.rb:89:in `run' +activesupport (7.2.3) lib/active_support/executor/test_helper.rb:5:in `block in run' +activesupport (7.2.3) lib/active_support/execution_wrapper.rb:104:in `perform' +activesupport (7.2.3) lib/active_support/executor/test_helper.rb:5:in `run' +minitest (5.26.2) lib/minitest.rb:1224:in `run_one_method' +minitest (5.26.2) lib/minitest.rb:463:in `run_one_method' +minitest (5.26.2) lib/minitest.rb:450:in `block (2 levels) in run' +minitest (5.26.2) lib/minitest.rb:446:in `each' +minitest (5.26.2) lib/minitest.rb:446:in `block in run' +minitest (5.26.2) lib/minitest.rb:488:in `on_signal' +minitest (5.26.2) lib/minitest.rb:475:in `with_info_handler' +minitest (5.26.2) lib/minitest.rb:445:in `run' +railties (7.2.3) lib/rails/test_unit/line_filtering.rb:10:in `run' +minitest (5.26.2) lib/minitest.rb:347:in `block in __run' +minitest (5.26.2) lib/minitest.rb:347:in `map' +minitest (5.26.2) lib/minitest.rb:347:in `__run' +minitest (5.26.2) lib/minitest.rb:302:in `run' +minitest (5.26.2) lib/minitest.rb:86:in `block in autorun' + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_bad_request_if_npc_parameter_missing +--------------------------------------------------------------------------------------- + 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.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.786366"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.786315"], ["updated_at", "2025-11-25 16:25:49.786315"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 400 Bad Request in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_404_for_non-existent_NPC +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.788898"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.788855"], ["updated_at", "2025-11-25 16:25:49.788855"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=non-existent-npc" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"non-existent-npc", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: non-existent-npc +[BreakEscape] Available NPCs: security_guard (test_room), test-npc (test_room) +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_npc-lazy-loader_should_construct_correct_API_endpoint_URL +---------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.791238"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.791206"], ["updated_at", "2025-11-25 16:25:49.791206"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/systems/npc-lazy-loader.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/npc-lazy-loader.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/npc-lazy-loader.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_phone-chat-ui_should_import_ASSETS_PATH_from_config +---------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.792958"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.792926"], ["updated_at", "2025-11-25 16:25:49.792926"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/phone-chat/phone-chat-ui.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/phone-chat/phone-chat-ui.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/phone-chat/phone-chat-ui.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GameTest: test_has_lockpick_in_inventory_should_find_lockpicks +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.794833"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.794803"], ["updated_at", "2025-11-25 16:25:49.794803"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=lockpick, scenarioData.type=, is_lockpick=true +[BreakEscape] Lockpick found in inventory: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------ +BreakEscape::GameTest: test_lockpick_should_bypass_key_requirement +------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.795976"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.795946"], ["updated_at", "2025-11-25 16:25:49.795946"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=secure_vault, attempt=, method=lockpick +[BreakEscape] Room data: locked=true, lockType=key, requires=vault_master_key +[BreakEscape] Room is LOCKED, method must be valid: lockpick +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=lockpick, scenarioData.type=, is_lockpick=true +[BreakEscape] Lockpick found in inventory: true +[BreakEscape] Lockpick validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------ +BreakEscape::GameTest: test_should_update_health +------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.797063"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.797035"], ["updated_at", "2025-11-25 16:25:49.797035"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":50}"], ["updated_at", "2025-11-25 16:25:49.797528"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------- +BreakEscape::GameTest: test_should_unlock_room +---------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.798408"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.798381"], ["updated_at", "2025-11-25 16:25:49.798381"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\",\"office\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:25:49.798838"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------- +BreakEscape::GameTest: test_should_reject_lockpick_unlock_without_lockpick_in_inventory +--------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.799681"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.799654"], ["updated_at", "2025-11-25 16:25:49.799654"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=lockpick +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: lockpick +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=key, scenarioData.type=, is_lockpick=false +[BreakEscape] Lockpick found in inventory: false +[BreakEscape] Lockpick validation result: false +[BreakEscape] validate_unlock returning: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------- +BreakEscape::GameTest: test_should_belong_to_player_and_mission +--------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.800708"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.800681"], ["updated_at", "2025-11-25 16:25:49.800681"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GameTest: test_has_key_in_inventory_should_find_keys_by_key_id +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.801639"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.801613"], ["updated_at", "2025-11-25 16:25:49.801613"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Checking for key office1_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=true +[BreakEscape] Key office1_key found in inventory: true +[BreakEscape] Checking for key wrong_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=false +[BreakEscape] Key wrong_key found in inventory: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::GameTest: test_should_allow_access_to_unlocked_doors_regardless_of_method +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.802590"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.802563"], ["updated_at", "2025-11-25 16:25:49.802563"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=reception, attempt=, method=unlocked +[BreakEscape] Door already unlocked in player state, granting access + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------- +BreakEscape::GameTest: test_should_clamp_health_between_0_and_100 +----------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.803510"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.803483"], ["updated_at", "2025-11-25 16:25:49.803483"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":0}"], ["updated_at", "2025-11-25 16:25:49.804025"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------- +BreakEscape::GameTest: test_has_lockpick_in_inventory_should_not_find_non-lockpick_items +---------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.804897"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.804871"], ["updated_at", "2025-11-25 16:25:49.804871"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=key, scenarioData.type=, is_lockpick=false +[BreakEscape] Lockpick found in inventory: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------- +BreakEscape::GameTest: test_should_track_inventory +-------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.805850"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.805823"], ["updated_at", "2025-11-25 16:25:49.805823"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"key\",\"name\":\"Test Key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:25:49.806359"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------- +BreakEscape::GameTest: test_should_validate_unlock_with_correct_key +------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.807220"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.807194"], ["updated_at", "2025-11-25 16:25:49.807194"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=key +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office1_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=true +[BreakEscape] Key office1_key found in inventory: true +[BreakEscape] Key validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------- +BreakEscape::GameTest: test_should_validate_unlock_with_lockpick +---------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.808196"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.808169"], ["updated_at", "2025-11-25 16:25:49.808169"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=lockpick +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: lockpick +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=lockpick, scenarioData.type=, is_lockpick=true +[BreakEscape] Lockpick found in inventory: true +[BreakEscape] Lockpick validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------- +BreakEscape::GameTest: test_should_reject_unlock_without_required_key +--------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.809941"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.809912"], ["updated_at", "2025-11-25 16:25:49.809912"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=key +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office1_key in inventory (1 items) +[BreakEscape] Inventory item: name=Wrong Key, key_id=wrong_key, is_match=false +[BreakEscape] Key office1_key found in inventory: false +[BreakEscape] Key validation result: false +[BreakEscape] validate_unlock returning: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------- +BreakEscape::GameTest: test_key_takes_precedence_over_lockpick_attempt +---------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.811016"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.810986"], ["updated_at", "2025-11-25 16:25:49.810986"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=key +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office1_key in inventory (2 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=true +[BreakEscape] Key office1_key found in inventory: true +[BreakEscape] Key validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::GameTest: test_should_reject_locked_door_without_any_unlock_method +------------------------------------------------------------------------------- + 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.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.812406"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.812375"], ["updated_at", "2025-11-25 16:25:49.812375"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method= +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: +[BreakEscape] SECURITY VIOLATION: No valid unlock method for LOCKED door: office1, method= +[BreakEscape] validate_unlock returning: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::RoomLazyLoadTest: test_should_return_400_when_room_id_is_missing +----------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.813887"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.813853"], ["updated_at", "2025-11-25 16:25:49.813853"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::RoomLazyLoadTest: test_should_return_room_data_for_valid_room_id +----------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.814941"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.814910"], ["updated_at", "2025-11-25 16:25:49.814910"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/room/test_room" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#room as HTML + Parameters: {"id"=>"1", "room_id"=>"test_room"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Serving room data for: test_room +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::RoomLazyLoadTest: test_should_return_404_for_non-existent_room +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.817514"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.817483"], ["updated_at", "2025-11-25 16:25:49.817483"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/room/non_existent_room" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#room as HTML + Parameters: {"id"=>"1", "room_id"=>"non_existent_room"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------ +BreakEscape::RoomLazyLoadTest: test_room_response_includes_all_room_data +------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:25:49.819827"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:25:49.819797"], ["updated_at", "2025-11-25 16:25:49.819797"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/room/test_room" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::GamesController#room as HTML + Parameters: {"id"=>"1", "room_id"=>"test_room"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Serving room data for: test_room +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_WOFF_font_content_type +---------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_GIF_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_WAV_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_MP3_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_JSON_content_type +----------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_is_case_insensitive +-------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_SVG_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_CSS_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_JavaScript_content_type +----------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_OGG_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_HTML_content_type +----------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_WOFF2_font_content_type +----------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_returns_octet-stream_for_unknown_extensions +-------------------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_PNG_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_TTF_font_content_type +--------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_handles_multiple_dots_in_filename +---------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_JPEG_content_type +----------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_all_response_headers_are_correct +------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_complete_asset_loading_path_for_lockpicking +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/lockpicking-game-phaser.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_click.mp3" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_click.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_click.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_overtension.mp3" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_overtension.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_overtension.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_reset.mp3" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_reset.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_reset.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_set.mp3" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_set.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_set.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_success.mp3" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_success.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_success.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_tension.mp3" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_tension.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_tension.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_wrong.mp3" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_wrong.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_wrong.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_minigame_starters +----------------------------------------------------------------------------- +Started GET "/break_escape/js/systems/minigame-starters.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/minigame-starters.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/minigame-starters.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_lockpicking_minigame +-------------------------------------------------------------------------------- +Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/lockpicking-game-phaser.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_door_tile_image +--------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door.png" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door.png (0.1ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_security:_cannot_access_files_outside_break_escape_directory +----------------------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/../../config/secrets.yml" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/secrets.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/js/../../config/database.yml" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/database.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/../../config/secrets.yml" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/secrets.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_CSS_files_should_be_accessible_from_main_game +-------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_route_constraints_correctly_capture_file_extensions +-------------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_should_load_GAME_CONFIG_with_proper_baseURL +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_asset_paths_work_without_assets_prefix_in_load_calls +--------------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_key-operations_minigame_module +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/minigames/lockpicking/key-operations.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/key-operations.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/key-operations.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_sound_manager_module +-------------------------------------------------------------------------------- +Started GET "/break_escape/js/systems/sound-manager.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/sound-manager.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/sound-manager.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_test_asset_page_loads_correctly +------------------------------------------------------------------------------ +Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as HTML + Parameters: {"filename"=>"test-assets"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/test-assets.html (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_game_core_with_asset_references +------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_baseURL_prevents_duplicate_asset_paths +------------------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_load_all_required_game_files_in_correct_order +--------------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:25:49 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + ActiveRecord::InternalMetadata Load (0.1ms) 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.0ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC + TRANSACTION (0.0ms) begin transaction +  (0.1ms) PRAGMA foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys +  (0.0ms) PRAGMA defer_foreign_keys = ON +  (0.0ms) PRAGMA foreign_keys = OFF + Fixtures Load (0.1ms) 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-25 16:27:19', '2025-11-25 16:27:19'); +INSERT INTO "break_escape_demo_users" ("id", "handle", "created_at", "updated_at") VALUES (618102942, 'other_user', '2025-11-25 16:27:19', '2025-11-25 16:27:19'); +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-25 16:27:19', '2025-11-25 16:27:19'); +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-25 16:27:19', '2025-11-25 16:27:19') +  (0.0ms) PRAGMA defer_foreign_keys = 0 +  (0.0ms) PRAGMA foreign_keys = 1 + TRANSACTION (0.8ms) commit transaction +  (0.0ms) PRAGMA foreign_key_check + TRANSACTION (0.0ms) begin transaction +--------------------------------------------- +BreakEscapeTest: test_it_has_a_version_number +--------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_returns_octet-stream_for_unknown_extensions +-------------------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_WAV_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_MP3_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_is_case_insensitive +-------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_HTML_content_type +----------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_handles_multiple_dots_in_filename +---------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_JavaScript_content_type +----------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_WOFF_font_content_type +---------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_PNG_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_CSS_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_SVG_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_WOFF2_font_content_type +----------------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_OGG_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_JSON_content_type +----------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_GIF_content_type +---------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_JPEG_content_type +----------------------------------------------------------------------------- + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerUnitTest: test_determines_TTF_font_content_type +--------------------------------------------------------------------------------- + TRANSACTION (0.0ms) 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.0ms) 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.1ms) 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-25 16:27:19.782515"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.782395"], ["updated_at", "2025-11-25 16:27:19.782395"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +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.0ms) 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.0ms) 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] Room data: locked=false, lockType=, requires= +[BreakEscape] Door is unlocked in scenario data, granting access + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:27:19.794001"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 4ms (Views: 0.1ms | ActiveRecord: 0.3ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) 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.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.796540"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.796466"], ["updated_at", "2025-11-25 16:27:19.796466"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:27:19.797184"], ["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-25 16:27:19 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:27:19.799061"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_unlockable_is_not_an_array +-------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.803274"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.803205"], ["updated_at", "2025-11-25 16:27:19.803205"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:27:19.804157"], ["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-25 16:27:19 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) 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.0ms) 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.1ms) 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-25 16:27:19.806999"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.806928"], ["updated_at", "2025-11-25 16:27:19.806928"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"terminal_bluetooth", "attempt"=>nil, "method"=>"bluetooth", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:27:19.808941"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) 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.0ms) 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.1ms) 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-25 16:27:19.810260"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.810198"], ["updated_at", "2025-11-25 16:27:19.810198"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_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\":[],\"inventory\":[],\"encounteredNPCs\":[\"helper_npc\"],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:27:19.810781"], ["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-25 16:27:19 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=fake_npc, target=office_pin +[BreakEscape] NPC not found: fake_npc +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_correct_PIN_should_unlock +--------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.812991"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.812853"], ["updated_at", "2025-11-25 16:27:19.812853"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:27:19.814795"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_NPC_unlock_adds_door_to_unlockedRooms +------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.816205"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.816126"], ["updated_at", "2025-11-25 16:27:19.816126"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:27:19.816711"], ["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-25 16:27:19 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin +[BreakEscape] NPC unlock validated: helper_npc can unlock office_pin + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:27:19.818307"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (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.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlock_non-existent_object_should_fail +-------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.819761"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.819698"], ["updated_at", "2025-11-25 16:27:19.819698"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_password_lock:_empty_attempt_should_fail +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.821978"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.821914"], ["updated_at", "2025-11-25 16:27:19.821914"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_multiple_unlock_attempts_should_update_state_correctly +------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.824192"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.824126"], ["updated_at", "2025-11-25 16:27:19.824126"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.9ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:27:19.829621"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 6ms (Views: 0.0ms | ActiveRecord: 1.0ms (5 queries, 0 cached) | GC: 4.5ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:27:19.839979"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 9ms (Views: 1.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 7.1ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) 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-25 16:27:19.849258"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 5ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 3.1ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_PIN_lock:_incorrect_PIN_should_fail +--------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.851582"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.851513"], ["updated_at", "2025-11-25 16:27:19.851513"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: false +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_RFID_lock:_should_trust_client_validation +-------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.854435"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.854371"], ["updated_at", "2025-11-25 16:27:19.854371"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"door_rfid", "attempt"=>nil, "method"=>"rfid", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:27:19.856426"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.3ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_lockpick:_should_trust_client_validation +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.857862"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.857796"], ["updated_at", "2025-11-25 16:27:19.857796"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"box_lockpick", "attempt"=>nil, "method"=>"lockpick", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:27:19.859537"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlock_with_invalid_method_should_fail +-------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.860922"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.860855"], ["updated_at", "2025-11-25 16:27:19.860855"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: invalid_method +[BreakEscape] SECURITY VIOLATION: No valid unlock method for LOCKED door: office_pin, method=invalid_method +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_NPC_can_unlock_door_if_player_has_encountered_them_and_NPC_has_permission +------------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.863331"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.863268"], ["updated_at", "2025-11-25 16:27:19.863268"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:27:19.863940"], ["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-25 16:27:19 +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.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin +[BreakEscape] NPC unlock validated: helper_npc can unlock office_pin + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:27:19.865530"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.3ms (5 queries, 0 cached) | GC: 0.1ms) + 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.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_correct_PIN_should_unlock +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.866948"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.866887"], ["updated_at", "2025-11-25 16:27:19.866887"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:27:19.868600"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + 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.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_key_lock:_should_trust_client_validation +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.870076"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.869942"], ["updated_at", "2025-11-25 16:27:19.869942"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"drawer_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:27:19.871723"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_unlock_response_should_filter_requires_from_contents +-------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.873090"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.873023"], ["updated_at", "2025-11-25 16:27:19.873023"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:27:19.874683"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_already-unlocked_container_accepts_method='unlocked' +---------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.875843"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.875770"], ["updated_at", "2025-11-25 16:27:19.875770"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:27:19.876364"], ["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-25 16:27:19 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:27:19.877891"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"npc_safe", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_SECURITY:_NPC_unlock_fails_if_player_has_not_encountered_NPC +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.880488"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.880424"], ["updated_at", "2025-11-25 16:27:19.880424"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:27:19.881042"], ["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-25 16:27:19 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=office_pin +[BreakEscape] Player has not encountered NPC: helper_npc +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_password_lock:_case_sensitivity +----------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.883246"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.883181"], ["updated_at", "2025-11-25 16:27:19.883181"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"OpenSesame", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: false +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_containers +----------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.885359"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.885296"], ["updated_at", "2025-11-25 16:27:19.885296"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +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.0ms) 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.0ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:27:19.887028"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_key_lock:_should_trust_client_validation +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.888229"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.888162"], ["updated_at", "2025-11-25 16:27:19.888162"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_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\":[],\"inventory\":[{\"id\":\"office_key\",\"type\":\"key\",\"name\":\"Office Key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:27:19.888797"], ["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-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_key", "attempt"=>nil, "method"=>"key", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=key, requires=office_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=, is_match=true +[BreakEscape] Key office_key found in inventory: true +[BreakEscape] Key validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"lobby\",\"unlockedRooms\":[\"lobby\",\"office_key\"],\"unlockedObjects\":[],\"inventory\":[{\"id\":\"office_key\",\"type\":\"key\",\"name\":\"Office Key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:27:19.890374"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_PIN_lock:_incorrect_PIN_should_fail +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.2ms) 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-25 16:27:19.891790"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.891715"], ["updated_at", "2025-11-25 16:27:19.891715"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>"0000", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_unlock_response_should_not_expose_'requires'_field_for_exploitable_locks +----------------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.894069"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.893978"], ["updated_at", "2025-11-25 16:27:19.893978"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:27:19.895708"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_SECURITY:_method='unlocked'_only_works_for_actually_unlocked_doors +------------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.896937"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.896872"], ["updated_at", "2025-11-25 16:27:19.896872"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=false, lockType=, requires= +[BreakEscape] Door is unlocked in scenario data, granting access + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:27:19.898584"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_password_lock:_incorrect_password_should_fail +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.899744"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.899678"], ["updated_at", "2025-11-25 16:27:19.899678"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"wrongpassword", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: false +[BreakEscape] validate_unlock returning: false +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_container_with_biometric_lock:_should_trust_client_validation +------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.901937"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.901869"], ["updated_at", "2025-11-25 16:27:19.901869"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"scanner_biometric", "attempt"=>nil, "method"=>"biometric", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:27:19.903601"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_container_with_password_lock:_correct_password_should_unlock +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.904781"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.904722"], ["updated_at", "2025-11-25 16:27:19.904722"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"cabinet_password", "attempt"=>"secret123", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:27:19.906476"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_door_with_password_lock:_correct_password_should_unlock +------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.907919"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.907855"], ["updated_at", "2025-11-25 16:27:19.907855"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_password", "attempt"=>"opensesame", "method"=>"password", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 +[BreakEscape] Room data: locked=true, lockType=password, requires=opensesame +[BreakEscape] Room is LOCKED, method must be valid: password +[BreakEscape] password validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:27:19.909557"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_locked_door_cannot_be_bypassed_with_method='unlocked' +--------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.910985"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.910907"], ["updated_at", "2025-11-25 16:27:19.910907"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: unlocked +[BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED door: office_pin +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_already-unlocked_door_accepts_method='unlocked' +----------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.913445"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.913380"], ["updated_at", "2025-11-25 16:27:19.913380"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:27:19.914017"], ["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-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"ceo", "attempt"=>"helper_npc", "method"=>"npc", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=password, requires=TopSecret123 +[BreakEscape] Room is LOCKED, method must be valid: npc +[BreakEscape] Validating NPC unlock: npc=helper_npc, target=ceo +[BreakEscape] NPC unlock validated: helper_npc can unlock ceo + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:27:19.915601"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"ceo", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------ +BreakEscape::UnlockSystemTest: test_unlock_non-existent_door_should_fail +------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.918207"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.918143"], ["updated_at", "2025-11-25 16:27:19.918143"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_SECURITY:_locked_container_cannot_be_bypassed_with_method='unlocked' +-------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.920407"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.920346"], ["updated_at", "2025-11-25 16:27:19.920346"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"safe_pin", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) 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.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.922991"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.922928"], ["updated_at", "2025-11-25 16:27:19.922928"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) 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-25 16:27:19.923647"], ["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-25 16:27:19 +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.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: 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 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlock_same_door_twice_should_be_idempotent +------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.926011"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.925948"], ["updated_at", "2025-11-25 16:27:19.925948"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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] Room data: locked=true, lockType=pin, requires=9876 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:27:19.927739"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office_pin", "attempt"=>"9876", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::UnlockSystemTest: test_unlocked_container:_should_grant_access_without_validation +---------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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-25 16:27:19.930639"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.930575"], ["updated_at", "2025-11-25 16:27:19.930575"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"object", "targetId"=>"chest_unlocked", "attempt"=>nil, "method"=>"unlocked", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) 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-25 16:27:19.932302"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::NPCInkLoadingTest: test_person-chat-portraits_should_import_ASSETS_PATH_from_config +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:19.933772"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.933738"], ["updated_at", "2025-11-25 16:27:19.933738"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/person-chat/person-chat-portraits.js" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/person-chat/person-chat-portraits.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/person-chat/person-chat-portraits.js (1.0ms) +Completed 200 OK in 1ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_phone-chat-ui_should_import_ASSETS_PATH_from_config +---------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:19.936745"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.936675"], ["updated_at", "2025-11-25 16:27:19.936675"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/phone-chat/phone-chat-ui.js" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/phone-chat/phone-chat-ui.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/phone-chat/phone-chat-ui.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_person-chat-minigame_should_use_Rails_API_endpoint_for_story_loading +--------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:19.938575"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.938543"], ["updated_at", "2025-11-25 16:27:19.938543"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/person-chat/person-chat-minigame.js?v=10" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"v"=>"10", "path"=>"minigames/person-chat/person-chat-minigame.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/person-chat/person-chat-minigame.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_404_for_non-existent_game +---------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:19.940388"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:19.940354"], ["updated_at", "2025-11-25 16:27:19.940354"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/999999/ink?npc=test-npc" for 127.0.0.1 at 2025-11-25 16:27:19 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"test-npc", "id"=>"999999"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 999999], ["LIMIT", 1]] +Completed 404 Not Found in 0ms (ActiveRecord: 0.0ms (1 query, 0 cached) | GC: 0.0ms) + +ActiveRecord::RecordNotFound (Couldn't find BreakEscape::Game with 'id'="999999"): + +activerecord (7.2.3) lib/active_record/core.rb:268:in `find' +/home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/controllers/break_escape/games_controller.rb:323:in `set_game' +activesupport (7.2.3) lib/active_support/callbacks.rb:362:in `block in make_lambda' +activesupport (7.2.3) lib/active_support/callbacks.rb:179:in `block in call' +actionpack (7.2.3) lib/abstract_controller/callbacks.rb:34:in `block (2 levels) in ' +activesupport (7.2.3) lib/active_support/callbacks.rb:180:in `call' +activesupport (7.2.3) lib/active_support/callbacks.rb:560:in `block in invoke_before' +activesupport (7.2.3) lib/active_support/callbacks.rb:560:in `each' +activesupport (7.2.3) lib/active_support/callbacks.rb:560:in `invoke_before' +activesupport (7.2.3) lib/active_support/callbacks.rb:119:in `block in run_callbacks' +actiontext (7.2.3) lib/action_text/rendering.rb:25:in `with_renderer' +actiontext (7.2.3) lib/action_text/engine.rb:71:in `block (4 levels) in ' +activesupport (7.2.3) lib/active_support/callbacks.rb:130:in `instance_exec' +activesupport (7.2.3) lib/active_support/callbacks.rb:130:in `block in run_callbacks' +activesupport (7.2.3) lib/active_support/callbacks.rb:141:in `run_callbacks' +actionpack (7.2.3) lib/abstract_controller/callbacks.rb:260:in `process_action' +actionpack (7.2.3) lib/action_controller/metal/rescue.rb:27:in `process_action' +actionpack (7.2.3) lib/action_controller/metal/instrumentation.rb:77:in `block in process_action' +activesupport (7.2.3) lib/active_support/notifications.rb:210:in `block in instrument' +activesupport (7.2.3) lib/active_support/notifications/instrumenter.rb:58:in `instrument' +activesupport (7.2.3) lib/active_support/notifications.rb:210:in `instrument' +actionpack (7.2.3) lib/action_controller/metal/instrumentation.rb:76:in `process_action' +actionpack (7.2.3) lib/action_controller/metal/params_wrapper.rb:259:in `process_action' +activerecord (7.2.3) lib/active_record/railties/controller_runtime.rb:39:in `process_action' +actionpack (7.2.3) lib/abstract_controller/base.rb:152:in `process' +actionview (7.2.3) lib/action_view/rendering.rb:40:in `process' +actionpack (7.2.3) lib/action_controller/metal.rb:252:in `dispatch' +actionpack (7.2.3) lib/action_controller/metal.rb:335:in `dispatch' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:67:in `dispatch' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:50:in `serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:53:in `block in serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:133:in `block in find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `each' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:34:in `serve' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:896:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/static.rb:27:in `call' +railties (7.2.3) lib/rails/engine.rb:535:in `call' +railties (7.2.3) lib/rails/railtie.rb:226:in `public_send' +railties (7.2.3) lib/rails/railtie.rb:226:in `method_missing' +actionpack (7.2.3) lib/action_dispatch/routing/mapper.rb:33:in `block in ' +actionpack (7.2.3) lib/action_dispatch/routing/mapper.rb:62:in `serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:53:in `block in serve' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:133:in `block in find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `each' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:126:in `find_routes' +actionpack (7.2.3) lib/action_dispatch/journey/router.rb:34:in `serve' +actionpack (7.2.3) lib/action_dispatch/routing/route_set.rb:896:in `call' +rack (3.2.4) lib/rack/tempfile_reaper.rb:20:in `call' +rack (3.2.4) lib/rack/etag.rb:29:in `call' +rack (3.2.4) lib/rack/conditional_get.rb:31:in `call' +rack (3.2.4) lib/rack/head.rb:15:in `call' +actionpack (7.2.3) lib/action_dispatch/http/permissions_policy.rb:38:in `call' +actionpack (7.2.3) lib/action_dispatch/http/content_security_policy.rb:38:in `call' +rack-session (2.1.1) lib/rack/session/abstract/id.rb:274:in `context' +rack-session (2.1.1) lib/rack/session/abstract/id.rb:268:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/cookies.rb:704:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/callbacks.rb:31:in `block in call' +activesupport (7.2.3) lib/active_support/callbacks.rb:101:in `run_callbacks' +actionpack (7.2.3) lib/action_dispatch/middleware/callbacks.rb:30:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/actionable_exceptions.rb:18:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/debug_exceptions.rb:31:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/show_exceptions.rb:32:in `call' +railties (7.2.3) lib/rails/rack/logger.rb:41:in `call_app' +railties (7.2.3) lib/rails/rack/logger.rb:29:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/remote_ip.rb:96:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/request_id.rb:33:in `call' +rack (3.2.4) lib/rack/method_override.rb:28:in `call' +rack (3.2.4) lib/rack/runtime.rb:24:in `call' +activesupport (7.2.3) lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/executor.rb:16:in `call' +actionpack (7.2.3) lib/action_dispatch/middleware/static.rb:27:in `call' +rack (3.2.4) lib/rack/sendfile.rb:131:in `call' +railties (7.2.3) lib/rails/engine.rb:535:in `call' +rack-test (2.2.0) lib/rack/test.rb:360:in `process_request' +rack-test (2.2.0) lib/rack/test.rb:153:in `request' +actionpack (7.2.3) lib/action_dispatch/testing/integration.rb:287:in `process' +actionpack (7.2.3) lib/action_dispatch/testing/integration.rb:19:in `get' +actionpack (7.2.3) lib/action_dispatch/testing/integration.rb:378:in `get' +/home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/test/integration/npc_ink_loading_test.rb:155:in `block in ' +minitest (5.26.2) lib/minitest/test.rb:95:in `block (2 levels) in run' +minitest (5.26.2) lib/minitest/test.rb:191:in `capture_exceptions' +minitest (5.26.2) lib/minitest/test.rb:90:in `block in run' +minitest (5.26.2) lib/minitest.rb:383:in `time_it' +minitest (5.26.2) lib/minitest/test.rb:89:in `run' +activesupport (7.2.3) lib/active_support/executor/test_helper.rb:5:in `block in run' +activesupport (7.2.3) lib/active_support/execution_wrapper.rb:104:in `perform' +activesupport (7.2.3) lib/active_support/executor/test_helper.rb:5:in `run' +minitest (5.26.2) lib/minitest.rb:1224:in `run_one_method' +minitest (5.26.2) lib/minitest.rb:463:in `run_one_method' +minitest (5.26.2) lib/minitest.rb:450:in `block (2 levels) in run' +minitest (5.26.2) lib/minitest.rb:446:in `each' +minitest (5.26.2) lib/minitest.rb:446:in `block in run' +minitest (5.26.2) lib/minitest.rb:488:in `on_signal' +minitest (5.26.2) lib/minitest.rb:475:in `with_info_handler' +minitest (5.26.2) lib/minitest.rb:445:in `run' +railties (7.2.3) lib/rails/test_unit/line_filtering.rb:10:in `run' +minitest (5.26.2) lib/minitest.rb:347:in `block in __run' +minitest (5.26.2) lib/minitest.rb:347:in `map' +minitest (5.26.2) lib/minitest.rb:347:in `__run' +minitest (5.26.2) lib/minitest.rb:302:in `run' +minitest (5.26.2) lib/minitest.rb:86:in `block in autorun' + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------ +BreakEscape::NPCInkLoadingTest: test_npc-barks_should_import_ASSETS_PATH_from_config +------------------------------------------------------------------------------------ + 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.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.080463"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.080406"], ["updated_at", "2025-11-25 16:27:20.080406"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/systems/npc-barks.js" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/npc-barks.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/npc-barks.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_ink_endpoint_should_return_application/json_content_type +--------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.082536"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.082496"], ["updated_at", "2025-11-25 16:27:20.082496"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=security_guard" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"security_guard", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: security_guard +[BreakEscape] Found NPC: security_guard with storyPath: scenarios/ink/security-guard.json +[BreakEscape] Serving ink from: /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/scenarios/ink/security-guard.json +Completed 200 OK in 1ms (Views: 0.3ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_404_for_NPC_without_story_file +--------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.085140"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.085107"], ["updated_at", "2025-11-25 16:27:20.085107"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=npc-with-no-file" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"npc-with-no-file", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: npc-with-no-file +[BreakEscape] Available NPCs: security_guard (test_room), test-npc (test_room) +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_phone-chat-minigame_should_use_Rails_API_endpoint_for_story_loading +-------------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.087159"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.087127"], ["updated_at", "2025-11-25 16:27:20.087127"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/minigames/phone-chat/phone-chat-minigame.js" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/phone-chat/phone-chat-minigame.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/phone-chat/phone-chat-minigame.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_npc-manager_should_load_stories_via_API_endpoint +------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.088734"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.088696"], ["updated_at", "2025-11-25 16:27:20.088696"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/systems/npc-manager.js" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/npc-manager.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/npc-manager.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_bad_request_if_npc_parameter_missing +--------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.090467"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.090434"], ["updated_at", "2025-11-25 16:27:20.090434"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 400 Bad Request in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_npc-lazy-loader_should_construct_correct_API_endpoint_URL +---------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.092469"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.092436"], ["updated_at", "2025-11-25 16:27:20.092436"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/js/systems/npc-lazy-loader.js" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/npc-lazy-loader.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/npc-lazy-loader.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_should_return_404_for_non-existent_NPC +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.094097"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.094064"], ["updated_at", "2025-11-25 16:27:20.094064"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=non-existent-npc" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"non-existent-npc", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: non-existent-npc +[BreakEscape] Available NPCs: security_guard (test_room), test-npc (test_room) +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::NPCInkLoadingTest: test_ink_endpoint_should_work_with_underscored_NPC_IDs +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"npcs\":[{\"id\":\"security_guard\",\"displayName\":\"Security Guard\",\"npcType\":\"person\",\"storyPath\":\"scenarios/ink/security-guard.json\"},{\"id\":\"test-npc\",\"displayName\":\"Test NPC\",\"npcType\":\"helper\",\"storyPath\":\"scenarios/ink/test-npc.json\"}]}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.096180"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.096148"], ["updated_at", "2025-11-25 16:27:20.096148"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=npc-with-underscores" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"npc-with-underscores", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: npc-with-underscores +[BreakEscape] Available NPCs: security_guard (test_room), test-npc (test_room) +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::GameTest: test_should_allow_access_to_unlocked_doors_regardless_of_method +-------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.098287"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.098258"], ["updated_at", "2025-11-25 16:27:20.098258"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=reception, attempt=, method=unlocked +[BreakEscape] Door already unlocked in player state, granting access + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------- +BreakEscape::GameTest: test_should_reject_lockpick_unlock_without_lockpick_in_inventory +--------------------------------------------------------------------------------------- + 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.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.100487"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.100456"], ["updated_at", "2025-11-25 16:27:20.100456"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=lockpick +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: lockpick +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=key, scenarioData.type=, is_lockpick=false +[BreakEscape] Lockpick found in inventory: false +[BreakEscape] Lockpick validation result: false +[BreakEscape] validate_unlock returning: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------ +BreakEscape::GameTest: test_should_update_health +------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.101498"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.101469"], ["updated_at", "2025-11-25 16:27:20.101469"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":50}"], ["updated_at", "2025-11-25 16:27:20.102209"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------- +BreakEscape::GameTest: test_should_unlock_room +---------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.103098"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.103068"], ["updated_at", "2025-11-25 16:27:20.103068"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\",\"office\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:27:20.103727"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------- +BreakEscape::GameTest: test_should_belong_to_player_and_mission +--------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.104570"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.104543"], ["updated_at", "2025-11-25 16:27:20.104543"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::GameTest: test_should_reject_locked_door_without_any_unlock_method +------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.105729"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.105696"], ["updated_at", "2025-11-25 16:27:20.105696"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method= +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: +[BreakEscape] SECURITY VIOLATION: No valid unlock method for LOCKED door: office1, method= +[BreakEscape] validate_unlock returning: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------- +BreakEscape::GameTest: test_should_track_inventory +-------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.106806"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.106770"], ["updated_at", "2025-11-25 16:27:20.106770"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"key\",\"name\":\"Test Key\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:27:20.107423"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------- +BreakEscape::GameTest: test_has_lockpick_in_inventory_should_not_find_non-lockpick_items +---------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.108302"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.108273"], ["updated_at", "2025-11-25 16:27:20.108273"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=key, scenarioData.type=, is_lockpick=false +[BreakEscape] Lockpick found in inventory: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GameTest: test_has_key_in_inventory_should_find_keys_by_key_id +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.109374"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.109347"], ["updated_at", "2025-11-25 16:27:20.109347"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Checking for key office1_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=true +[BreakEscape] Key office1_key found in inventory: true +[BreakEscape] Checking for key wrong_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=false +[BreakEscape] Key wrong_key found in inventory: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------- +BreakEscape::GameTest: test_should_validate_unlock_with_correct_key +------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.2ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.110334"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.110306"], ["updated_at", "2025-11-25 16:27:20.110306"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=key +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office1_key in inventory (1 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=true +[BreakEscape] Key office1_key found in inventory: true +[BreakEscape] Key validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------- +BreakEscape::GameTest: test_should_clamp_health_between_0_and_100 +----------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.111442"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.111415"], ["updated_at", "2025-11-25 16:27:20.111415"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":0}"], ["updated_at", "2025-11-25 16:27:20.111990"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------ +BreakEscape::GameTest: test_lockpick_should_bypass_key_requirement +------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.113012"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.112983"], ["updated_at", "2025-11-25 16:27:20.112983"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=secure_vault, attempt=, method=lockpick +[BreakEscape] Room data: locked=true, lockType=key, requires=vault_master_key +[BreakEscape] Room is LOCKED, method must be valid: lockpick +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=lockpick, scenarioData.type=, is_lockpick=true +[BreakEscape] Lockpick found in inventory: true +[BreakEscape] Lockpick validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------- +BreakEscape::GameTest: test_should_validate_unlock_with_lockpick +---------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.114060"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.114032"], ["updated_at", "2025-11-25 16:27:20.114032"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=lockpick +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: lockpick +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=lockpick, scenarioData.type=, is_lockpick=true +[BreakEscape] Lockpick found in inventory: true +[BreakEscape] Lockpick validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------- +BreakEscape::GameTest: test_key_takes_precedence_over_lockpick_attempt +---------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.115043"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.115016"], ["updated_at", "2025-11-25 16:27:20.115016"]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=key +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office1_key in inventory (2 items) +[BreakEscape] Inventory item: name=Office Key, key_id=office1_key, is_match=true +[BreakEscape] Key office1_key found in inventory: true +[BreakEscape] Key validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------- +BreakEscape::GameTest: test_should_reject_unlock_without_required_key +--------------------------------------------------------------------- + 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.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.116098"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.116071"], ["updated_at", "2025-11-25 16:27:20.116071"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] validate_unlock: type=door, id=office1, attempt=, method=key +[BreakEscape] Room data: locked=true, lockType=key, requires=office1_key +[BreakEscape] Room is LOCKED, method must be valid: key +[BreakEscape] Checking for key office1_key in inventory (1 items) +[BreakEscape] Inventory item: name=Wrong Key, key_id=wrong_key, is_match=false +[BreakEscape] Key office1_key found in inventory: false +[BreakEscape] Key validation result: false +[BreakEscape] validate_unlock returning: false + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GameTest: test_has_lockpick_in_inventory_should_find_lockpicks +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"rooms\":{}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.117127"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.117100"], ["updated_at", "2025-11-25 16:27:20.117100"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Checking for lockpick in inventory (1 items) +[BreakEscape] Inventory item: type=lockpick, scenarioData.type=, is_lockpick=true +[BreakEscape] Lockpick found in inventory: true + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_removes_objects_and_npcs +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.118376"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.118330"], ["updated_at", "2025-11-25 16:27:20.118330"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_does_not_modify_original +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.119474"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.119434"], ["updated_at", "2025-11-25 16:27:20.119434"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_removes_room_contents +--------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.120421"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.120383"], ["updated_at", "2025-11-25 16:27:20.120383"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------------ +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_preserves_navigation_structure +------------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.121442"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.121404"], ["updated_at", "2025-11-25 16:27:20.121404"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::FilteredScenarioTest: test_filtered_scenario_for_bootstrap_preserves_lock_requirements +--------------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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", "{\"scenario_brief\":\"Test mission\",\"startRoom\":\"start\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"rooms\":{\"start\":{\"type\":\"room_office\",\"connections\":{\"north\":\"next_room\"},\"locked\":false,\"objects\":[{\"type\":\"desk\",\"name\":\"Desk\",\"takeable\":false}],\"npcs\":[{\"id\":\"npc1\",\"displayName\":\"NPC One\"}]},\"next_room\":{\"type\":\"room_server\",\"connections\":{\"south\":\"start\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"key123\",\"objects\":[{\"type\":\"server\",\"name\":\"Server\",\"takeable\":false}]}}}"], ["player_state", "{\"currentRoom\":\"start\",\"unlockedRooms\":[\"start\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Test Phone\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.122419"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.122382"], ["updated_at", "2025-11-25 16:27:20.122382"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_get_index +---------------------------------------------------------- +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.0ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" = ? [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.2ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 5.8ms | GC: 0.2ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 6.0ms | GC: 0.2ms) +Completed 200 OK in 7ms (Views: 6.2ms | ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.2ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_index_should_display_published_missions +--------------------------------------------------------------------------------- +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.0ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" = ? [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 0.6ms | GC: 0.1ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.7ms | GC: 0.1ms) +Completed 200 OK in 1ms (Views: 0.8ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_show_published_mission +----------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] +Started GET "/break_escape/missions/418560898" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::MissionsController#show as HTML + Parameters: {"id"=>"418560898"} + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::Game Load (0.1ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."player_type" = ? AND "break_escape_games"."player_id" = ? AND "break_escape_games"."mission_id" = ? LIMIT ? [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) 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", "{\"scenario_brief\":\"Hi! You are a cyber investigator tasked with uncovering evidence of corporate espionage. Anonymous tips suggest the CEO has been selling company secrets, but you need proof.\",\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office1\"},\"npcs\":[{\"id\":\"neye_eve\",\"displayName\":\"Neye Eve\",\"storyPath\":\"scenarios/ink/neye-eve.json\",\"avatar\":\"assets/npc/avatars/npc_adversary.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\"},{\"id\":\"gossip_girl\",\"displayName\":\"Gossip Girl\",\"storyPath\":\"scenarios/ink/gossip-girl.json\",\"avatar\":\"assets/npc/avatars/npc_neutral.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"timedMessages\":[{\"delay\":5000,\"message\":\"Hey! 👋 Got any juicy gossip for me today?\",\"type\":\"text\"}]},{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"storyPath\":\"scenarios/ink/helper-npc.json\",\"avatar\":\"assets/npc/avatars/npc_helper.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"unlockable\":[\"secure_vault\",\"ceo\"],\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":15000},{\"eventPattern\":\"door_unlocked\",\"targetKnot\":\"on_door_unlocked\",\"cooldown\":8000},{\"eventPattern\":\"door_unlock_attempt\",\"targetKnot\":\"on_door_attempt\",\"cooldown\":12000},{\"eventPattern\":\"object_interacted\",\"targetKnot\":\"on_ceo_desk_interact\",\"condition\":\"data.objectType === 'desk_ceo'\",\"cooldown\":10000},{\"eventPattern\":\"item_picked_up:*\",\"targetKnot\":\"on_item_found\",\"cooldown\":20000},{\"eventPattern\":\"room_entered\",\"targetKnot\":\"on_room_entered\",\"cooldown\":45000,\"maxTriggers\":3},{\"eventPattern\":\"room_discovered\",\"targetKnot\":\"on_room_discovered\",\"cooldown\":15000,\"maxTriggers\":5},{\"eventPattern\":\"room_entered:ceo\",\"targetKnot\":\"on_ceo_office_entered\",\"onceOnly\":true}]}],\"objects\":[{\"type\":\"phone\",\"name\":\"Reception Phone\",\"takeable\":false,\"readable\":true,\"voice\":\"Hi, this is the IT Team. Security breach detected in server room. Changed access code to 4829.\",\"sender\":\"IT Team\",\"timestamp\":\"2:15 AM\",\"observations\":\"The reception phone's message light is blinking urgently\"},{\"type\":\"notes\",\"name\":\"Security Log\",\"takeable\":true,\"readable\":true,\"text\":\"Unusual after-hours access detected:\\n- CEO office: 11:30 PM\\n- Server room: 2:15 AM\\n- CEO office again: 3:45 AM\",\"observations\":\"A concerning security log from last night\"},{\"type\":\"pc\",\"name\":\"Reception Computer\",\"takeable\":false,\"lockType\":\"password\",\"passwordHint\":\"Optional hint text\",\"showHint\":true,\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"requires\":\"secret123\",\"observations\":\"The reception's computer, currently locked\",\"postitNote\":\"Password: secret123\",\"showPostit\":true,\"contents\":[{\"type\":\"text_file\",\"name\":\"Private\",\"takeable\":false,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\"}]},{\"type\":\"tablet\",\"name\":\"Tablet Device\",\"takeable\":true,\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"A locked tablet device that requires Bluetooth pairing\"},{\"type\":\"bluetooth_scanner\",\"name\":\"Bluetooth Scanner\",\"takeable\":true,\"observations\":\"A device for detecting nearby Bluetooth signals\",\"canScanBluetooth\":true},{\"type\":\"key\",\"name\":\"Office Key\",\"takeable\":true,\"key_id\":\"office1_key\",\"keyPins\":[65,25,65,25],\"observations\":\"A key to access the office areas\"},{\"type\":\"pin-cracker\",\"name\":\"PIN Cracker\",\"takeable\":true,\"observations\":\"A sophisticated device that can analyze PIN entry patterns and provide feedback on attempts\"},{\"type\":\"safe\",\"name\":\"Reception Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9573\",\"observations\":\"A small wall safe behind the reception desk. Looks like it needs a 4-digit code.\",\"contents\":[{\"type\":\"notes\",\"name\":\"IT Access Credentials\",\"takeable\":true,\"readable\":true,\"text\":\"Emergency IT Admin Credentials:\\nUsername: admin\\nPassword: ITsecure2024\\n\\nServer Room Backup Code: 4829\\nCEO Office Alarm Override: 1337\",\"observations\":\"Sensitive IT credentials that could be very useful\"}]}]},\"office1\":{\"type\":\"room_office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office1_key\",\"keyPins\":[65,25,65,25],\"difficulty\":\"easy\",\"door_sign\":\"4A Hot Desks\",\"connections\":{\"north\":[\"office2\",\"office3\"],\"south\":\"reception\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"requires\":\"password\",\"hasFingerprint\":true,\"fingerprintOwner\":\"ceo\",\"fingerprintDifficulty\":\"medium\",\"observations\":\"A computer with a cybersecurity alert on screen. There might be fingerprints on the keyboard.\"},{\"type\":\"notes\",\"name\":\"IT Memo\",\"takeable\":true,\"readable\":true,\"text\":\"URGENT: Multiple unauthorized access attempts detected from CEO's office IP address\",\"observations\":\"A concerning IT department memo\"},{\"type\":\"fingerprint_kit\",\"name\":\"Fingerprint Kit\",\"takeable\":true,\"observations\":\"A kit used for collecting fingerprints from surfaces\"}]},\"office2\":{\"type\":\"room_office\",\"connections\":{\"north\":\"ceo\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"office2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: office2024\",\"showPostit\":true,\"observations\":\"A standard office computer with a sticky note on the monitor\"},{\"type\":\"notes\",\"name\":\"Shredded Document\",\"takeable\":true,\"readable\":true,\"text\":\"Partially readable: '...offshore account...transfer complete...delete all traces...'\",\"observations\":\"A partially shredded document that someone failed to dispose of properly\"},{\"type\":\"key\",\"name\":\"CEO Office Key\",\"takeable\":true,\"key_id\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"observations\":\"A spare key to the CEO's office, carelessly left behind\"}]},\"office3\":{\"type\":\"room_office\",\"connections\":{\"north\":\"server1\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"IT Staff Computer\",\"takeable\":false,\"requires\":\"bluetooth\",\"lockType\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"An IT staff computer showing network security logs\"},{\"type\":\"notes\",\"name\":\"Network Logs\",\"takeable\":true,\"readable\":true,\"text\":\"Large data transfers detected to unknown external IPs - All originating from CEO's office\",\"observations\":\"Suspicious network activity logs\"}]},\"ceo\":{\"type\":\"room_ceo\",\"connections\":{\"north\":\"closet\",\"south\":\"office2\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"difficulty\":\"easy\",\"objects\":[{\"type\":\"pc\",\"name\":\"CEO Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"ceo2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: ceo2024\",\"showPostit\":true,\"observations\":\"The CEO's laptop, still warm - recently used. A sticky note is attached to the screen.\"},{\"type\":\"suitcase\",\"name\":\"CEO Briefcase\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"difficulty\":\"medium\",\"observations\":\"An expensive leather briefcase with a sturdy lock\",\"contents\":[{\"type\":\"notes\",\"name\":\"Private Note\",\"takeable\":true,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\",\"observations\":\"A hastily written note on expensive paper\"},{\"type\":\"key\",\"name\":\"Safe Key\",\"takeable\":true,\"key_id\":\"safe_key\",\"keyPins\":[52,29,44,37],\"observations\":\"A heavy-duty safe key hidden behind server equipment\"}]},{\"type\":\"phone\",\"name\":\"CEO Phone\",\"takeable\":false,\"readable\":true,\"text\":\"Recent calls: 'Offshore Bank', 'Unknown', 'Data Buyer'\",\"sender\":\"Call Log\",\"timestamp\":\"Last 24 hours\",\"observations\":\"The CEO's phone shows suspicious recent calls\"}]},\"closet\":{\"type\":\"room_closet\",\"connections\":{\"south\":\"ceo\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"7391\",\"objects\":[{\"type\":\"safe\",\"name\":\"Hidden Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"safe_key\",\"keyPins\":[52,29,44,37],\"difficulty\":\"hard\",\"observations\":\"A well-hidden wall safe behind a painting\",\"contents\":[{\"type\":\"notes\",\"name\":\"Incriminating Documents\",\"takeable\":true,\"readable\":true,\"text\":\"Contract for sale of proprietary technology\\nBank transfers from competing companies\\nDetails of upcoming corporate espionage operations\",\"observations\":\"A folder containing damning evidence of corporate espionage. Congratulations! You've recovered the incriminating documents. flag{ceo_exfil_flag}\"}]}]},\"server1\":{\"type\":\"room_servers\",\"connections\":{\"south\":\"office3\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"4829\",\"objects\":[{\"type\":\"pc\",\"name\":\"Server Terminal\",\"takeable\":false,\"observations\":\"The main server terminal showing massive data exfiltration\"},{\"type\":\"key\",\"name\":\"Briefcase Key\",\"takeable\":true,\"key_id\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.136588"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.135952"], ["updated_at", "2025-11-25 16:27:20.135952"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Redirected to http://www.example.com/break_escape/games/1 +Completed 302 Found in 2ms (ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::MissionsControllerTest: test_should_create_game_and_redirect_when_showing_mission +---------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Count (0.0ms) SELECT COUNT(*) FROM "break_escape_games" +Started GET "/break_escape/missions/418560898" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::MissionsController#show as HTML + Parameters: {"id"=>"418560898"} + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."player_type" = ? AND "break_escape_games"."player_id" = ? AND "break_escape_games"."mission_id" = ? LIMIT ? [["player_type", "BreakEscape::DemoUser"], ["player_id", 149617800], ["mission_id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Create (0.1ms) 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", "{\"scenario_brief\":\"Hi! You are a cyber investigator tasked with uncovering evidence of corporate espionage. Anonymous tips suggest the CEO has been selling company secrets, but you need proof.\",\"startRoom\":\"reception\",\"startItemsInInventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office1\"},\"npcs\":[{\"id\":\"neye_eve\",\"displayName\":\"Neye Eve\",\"storyPath\":\"scenarios/ink/neye-eve.json\",\"avatar\":\"assets/npc/avatars/npc_adversary.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\"},{\"id\":\"gossip_girl\",\"displayName\":\"Gossip Girl\",\"storyPath\":\"scenarios/ink/gossip-girl.json\",\"avatar\":\"assets/npc/avatars/npc_neutral.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"timedMessages\":[{\"delay\":5000,\"message\":\"Hey! 👋 Got any juicy gossip for me today?\",\"type\":\"text\"}]},{\"id\":\"helper_npc\",\"displayName\":\"Helpful Contact\",\"storyPath\":\"scenarios/ink/helper-npc.json\",\"avatar\":\"assets/npc/avatars/npc_helper.png\",\"phoneId\":\"player_phone\",\"currentKnot\":\"start\",\"npcType\":\"phone\",\"unlockable\":[\"secure_vault\",\"ceo\"],\"eventMappings\":[{\"eventPattern\":\"item_picked_up:lockpick\",\"targetKnot\":\"on_lockpick_pickup\",\"onceOnly\":true,\"cooldown\":0},{\"eventPattern\":\"minigame_completed\",\"targetKnot\":\"on_lockpick_success\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":10000},{\"eventPattern\":\"minigame_failed\",\"targetKnot\":\"on_lockpick_failed\",\"condition\":\"data.minigameName \\u0026\\u0026 data.minigameName.includes('Lockpick')\",\"cooldown\":15000},{\"eventPattern\":\"door_unlocked\",\"targetKnot\":\"on_door_unlocked\",\"cooldown\":8000},{\"eventPattern\":\"door_unlock_attempt\",\"targetKnot\":\"on_door_attempt\",\"cooldown\":12000},{\"eventPattern\":\"object_interacted\",\"targetKnot\":\"on_ceo_desk_interact\",\"condition\":\"data.objectType === 'desk_ceo'\",\"cooldown\":10000},{\"eventPattern\":\"item_picked_up:*\",\"targetKnot\":\"on_item_found\",\"cooldown\":20000},{\"eventPattern\":\"room_entered\",\"targetKnot\":\"on_room_entered\",\"cooldown\":45000,\"maxTriggers\":3},{\"eventPattern\":\"room_discovered\",\"targetKnot\":\"on_room_discovered\",\"cooldown\":15000,\"maxTriggers\":5},{\"eventPattern\":\"room_entered:ceo\",\"targetKnot\":\"on_ceo_office_entered\",\"onceOnly\":true}]}],\"objects\":[{\"type\":\"phone\",\"name\":\"Reception Phone\",\"takeable\":false,\"readable\":true,\"voice\":\"Hi, this is the IT Team. Security breach detected in server room. Changed access code to 4829.\",\"sender\":\"IT Team\",\"timestamp\":\"2:15 AM\",\"observations\":\"The reception phone's message light is blinking urgently\"},{\"type\":\"notes\",\"name\":\"Security Log\",\"takeable\":true,\"readable\":true,\"text\":\"Unusual after-hours access detected:\\n- CEO office: 11:30 PM\\n- Server room: 2:15 AM\\n- CEO office again: 3:45 AM\",\"observations\":\"A concerning security log from last night\"},{\"type\":\"pc\",\"name\":\"Reception Computer\",\"takeable\":false,\"lockType\":\"password\",\"passwordHint\":\"Optional hint text\",\"showHint\":true,\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"requires\":\"secret123\",\"observations\":\"The reception's computer, currently locked\",\"postitNote\":\"Password: secret123\",\"showPostit\":true,\"contents\":[{\"type\":\"text_file\",\"name\":\"Private\",\"takeable\":false,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\"}]},{\"type\":\"tablet\",\"name\":\"Tablet Device\",\"takeable\":true,\"locked\":true,\"lockType\":\"bluetooth\",\"requires\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"A locked tablet device that requires Bluetooth pairing\"},{\"type\":\"bluetooth_scanner\",\"name\":\"Bluetooth Scanner\",\"takeable\":true,\"observations\":\"A device for detecting nearby Bluetooth signals\",\"canScanBluetooth\":true},{\"type\":\"key\",\"name\":\"Office Key\",\"takeable\":true,\"key_id\":\"office1_key\",\"keyPins\":[65,25,65,25],\"observations\":\"A key to access the office areas\"},{\"type\":\"pin-cracker\",\"name\":\"PIN Cracker\",\"takeable\":true,\"observations\":\"A sophisticated device that can analyze PIN entry patterns and provide feedback on attempts\"},{\"type\":\"safe\",\"name\":\"Reception Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"pin\",\"requires\":\"9573\",\"observations\":\"A small wall safe behind the reception desk. Looks like it needs a 4-digit code.\",\"contents\":[{\"type\":\"notes\",\"name\":\"IT Access Credentials\",\"takeable\":true,\"readable\":true,\"text\":\"Emergency IT Admin Credentials:\\nUsername: admin\\nPassword: ITsecure2024\\n\\nServer Room Backup Code: 4829\\nCEO Office Alarm Override: 1337\",\"observations\":\"Sensitive IT credentials that could be very useful\"}]}]},\"office1\":{\"type\":\"room_office\",\"locked\":true,\"lockType\":\"key\",\"requires\":\"office1_key\",\"keyPins\":[65,25,65,25],\"difficulty\":\"easy\",\"door_sign\":\"4A Hot Desks\",\"connections\":{\"north\":[\"office2\",\"office3\"],\"south\":\"reception\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"requires\":\"password\",\"hasFingerprint\":true,\"fingerprintOwner\":\"ceo\",\"fingerprintDifficulty\":\"medium\",\"observations\":\"A computer with a cybersecurity alert on screen. There might be fingerprints on the keyboard.\"},{\"type\":\"notes\",\"name\":\"IT Memo\",\"takeable\":true,\"readable\":true,\"text\":\"URGENT: Multiple unauthorized access attempts detected from CEO's office IP address\",\"observations\":\"A concerning IT department memo\"},{\"type\":\"fingerprint_kit\",\"name\":\"Fingerprint Kit\",\"takeable\":true,\"observations\":\"A kit used for collecting fingerprints from surfaces\"}]},\"office2\":{\"type\":\"room_office\",\"connections\":{\"north\":\"ceo\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"Office Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"office2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: office2024\",\"showPostit\":true,\"observations\":\"A standard office computer with a sticky note on the monitor\"},{\"type\":\"notes\",\"name\":\"Shredded Document\",\"takeable\":true,\"readable\":true,\"text\":\"Partially readable: '...offshore account...transfer complete...delete all traces...'\",\"observations\":\"A partially shredded document that someone failed to dispose of properly\"},{\"type\":\"key\",\"name\":\"CEO Office Key\",\"takeable\":true,\"key_id\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"observations\":\"A spare key to the CEO's office, carelessly left behind\"}]},\"office3\":{\"type\":\"room_office\",\"connections\":{\"north\":\"server1\",\"south\":\"office1\"},\"objects\":[{\"type\":\"pc\",\"name\":\"IT Staff Computer\",\"takeable\":false,\"requires\":\"bluetooth\",\"lockType\":\"bluetooth\",\"mac\":\"00:11:22:33:44:55\",\"observations\":\"An IT staff computer showing network security logs\"},{\"type\":\"notes\",\"name\":\"Network Logs\",\"takeable\":true,\"readable\":true,\"text\":\"Large data transfers detected to unknown external IPs - All originating from CEO's office\",\"observations\":\"Suspicious network activity logs\"}]},\"ceo\":{\"type\":\"room_ceo\",\"connections\":{\"north\":\"closet\",\"south\":\"office2\"},\"locked\":true,\"lockType\":\"key\",\"requires\":\"ceo_office_key\",\"keyPins\":[25,45,65,75],\"difficulty\":\"easy\",\"objects\":[{\"type\":\"pc\",\"name\":\"CEO Computer\",\"takeable\":false,\"lockType\":\"password\",\"requires\":\"ceo2024\",\"showKeyboard\":true,\"maxAttempts\":3,\"locked\":true,\"postitNote\":\"Password: ceo2024\",\"showPostit\":true,\"observations\":\"The CEO's laptop, still warm - recently used. A sticky note is attached to the screen.\"},{\"type\":\"suitcase\",\"name\":\"CEO Briefcase\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"difficulty\":\"medium\",\"observations\":\"An expensive leather briefcase with a sturdy lock\",\"contents\":[{\"type\":\"notes\",\"name\":\"Private Note\",\"takeable\":true,\"readable\":true,\"text\":\"Closet keypad code: 7391 - Must move evidence to safe before audit\",\"observations\":\"A hastily written note on expensive paper\"},{\"type\":\"key\",\"name\":\"Safe Key\",\"takeable\":true,\"key_id\":\"safe_key\",\"keyPins\":[52,29,44,37],\"observations\":\"A heavy-duty safe key hidden behind server equipment\"}]},{\"type\":\"phone\",\"name\":\"CEO Phone\",\"takeable\":false,\"readable\":true,\"text\":\"Recent calls: 'Offshore Bank', 'Unknown', 'Data Buyer'\",\"sender\":\"Call Log\",\"timestamp\":\"Last 24 hours\",\"observations\":\"The CEO's phone shows suspicious recent calls\"}]},\"closet\":{\"type\":\"room_closet\",\"connections\":{\"south\":\"ceo\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"7391\",\"objects\":[{\"type\":\"safe\",\"name\":\"Hidden Safe\",\"takeable\":false,\"locked\":true,\"lockType\":\"key\",\"requires\":\"safe_key\",\"keyPins\":[52,29,44,37],\"difficulty\":\"hard\",\"observations\":\"A well-hidden wall safe behind a painting\",\"contents\":[{\"type\":\"notes\",\"name\":\"Incriminating Documents\",\"takeable\":true,\"readable\":true,\"text\":\"Contract for sale of proprietary technology\\nBank transfers from competing companies\\nDetails of upcoming corporate espionage operations\",\"observations\":\"A folder containing damning evidence of corporate espionage. Congratulations! You've recovered the incriminating documents. flag{ceo_exfil_flag}\"}]}]},\"server1\":{\"type\":\"room_servers\",\"connections\":{\"south\":\"office3\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"4829\",\"objects\":[{\"type\":\"pc\",\"name\":\"Server Terminal\",\"takeable\":false,\"observations\":\"The main server terminal showing massive data exfiltration\"},{\"type\":\"key\",\"name\":\"Briefcase Key\",\"takeable\":true,\"key_id\":\"briefcase_key\",\"keyPins\":[45,35,25,55],\"observations\":\"A small key labeled 'Personal - Do Not Copy'\"}]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"phone\",\"name\":\"Your Phone\",\"takeable\":true,\"phoneId\":\"player_phone\",\"npcIds\":[\"neye_eve\",\"gossip_girl\",\"helper_npc\"],\"observations\":\"Your personal phone with some interesting contacts\"},{\"type\":\"workstation\",\"name\":\"Crypto Analysis Station\",\"takeable\":true,\"observations\":\"A powerful workstation for cryptographic analysis\"},{\"type\":\"lockpick\",\"name\":\"Lock Pick Kit\",\"takeable\":true,\"observations\":\"A professional lock picking kit with various picks and tension wrenches\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.139814"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.139143"], ["updated_at", "2025-11-25 16:27:20.139143"]] + TRANSACTION (0.1ms) RELEASE SAVEPOINT active_record_1 +Redirected to http://www.example.com/break_escape/games/1 +Completed 302 Found in 2ms (ActiveRecord: 0.3ms (4 queries, 0 cached) | GC: 0.1ms) + BreakEscape::Game Count (0.0ms) SELECT COUNT(*) FROM "break_escape_games" + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------ +BreakEscape::MissionsControllerTest: test_index_should_return_HTML_with_mission_list +------------------------------------------------------------------------------------ +Started GET "/break_escape/missions" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::MissionsController#index as HTML + BreakEscape::DemoUser Load (0.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" ORDER BY "break_escape_demo_users"."id" ASC LIMIT ? [["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application + BreakEscape::Mission Pluck (0.0ms) SELECT DISTINCT "break_escape_missions"."collection" FROM "break_escape_missions" + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? [["published", 1]] + BreakEscape::Cybok Load (0.0ms) SELECT "break_escape_cyboks".* FROM "break_escape_cyboks" WHERE "break_escape_cyboks"."cybokable_type" = ? AND "break_escape_cyboks"."cybokable_id" = ? [["cybokable_type", "BreakEscape::Mission"], ["cybokable_id", 418560898]] + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/shared/_cybok_label.html.erb (Duration: 0.0ms | GC: 0.0ms) + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/missions/index.html.erb within layouts/break_escape/application (Duration: 0.5ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.5ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.6ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Routes:_should_capture_complex_paths_with_segments +----------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Security:_should_prevent_directory_traversal_in_CSS +------------------------------------------------------------------------------------------------ +Started GET "/break_escape/css/../../config/database.yml" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/database.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.2ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Assets:_should_return_404_for_non-existent_files +--------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/non-existent.mp3" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/non-existent.mp3"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Phaser:_constants_define_GAME_CONFIG_with_baseURL +---------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Assets:_should_serve_audio_with_correct_MIME_type +---------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_JS:_should_serve_files_with_correct_MIME_type +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_CSS:_should_serve_with_inline_disposition +-------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_audio_files_are_non-empty +--------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Routes:_should_capture_full_filename_with_extension +------------------------------------------------------------------------------------------------ +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_JS:_should_serve_nested_files +-------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.1ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Minigame:_should_serve_lockpicking_sounds +-------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_click.mp3" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_click.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_click.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_success.mp3" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_success.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_success.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Headers:_should_set_Content-Disposition_to_inline +---------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_CSS:_should_serve_files_with_correct_MIME_type +------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Routes:_should_handle_files_with_multiple_dots +------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door_sheet_32.png" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_sheet_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_sheet_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Minigame:_should_serve_lockpicking_script +-------------------------------------------------------------------------------------- +Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/lockpicking-game-phaser.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_JavaScript_files_are_non-empty +-------------------------------------------------------------------------------------- +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Phaser:_main_JS_imports_GAME_CONFIG +-------------------------------------------------------------------------------- +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_image_files_are_non-empty +--------------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Security:_should_prevent_directory_traversal_in_JS +----------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/../../config/secrets.yml" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/secrets.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Security:_should_prevent_directory_traversal_in_assets +--------------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/../../config/database.yml" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/database.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_HTML:_should_serve_test_files_with_correct_MIME_type +------------------------------------------------------------------------------------------------- +Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as HTML + Parameters: {"filename"=>"test-assets"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/test-assets.html (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Integrity:_CSS_files_are_non-empty +------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_JS:_should_return_404_for_non-existent_files +----------------------------------------------------------------------------------------- +Started GET "/break_escape/js/non-existent.js" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"non-existent.js"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Headers:_should_include_Cache-Control +---------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Phaser:_game.js_has_asset_references_without_prefix +------------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_HTML:_should_return_404_for_non-existent_files +------------------------------------------------------------------------------------------- +Started GET "/break_escape/non-existent.html" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 + +ActionController::RoutingError (No route matches [GET] "/break_escape/non-existent.html"): + + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_CSS:_should_return_404_for_non-existent_files +------------------------------------------------------------------------------------------ +Started GET "/break_escape/css/non-existent.css" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"non-existent.css"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Assets:_should_serve_PNG_tiles_with_correct_MIME_type +-------------------------------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_Assets:_should_serve_nested_files +------------------------------------------------------------------------------ +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------- +BreakEscape::StaticFilesControllerTest: test_Headers:_should_include_Content-Length +----------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::StaticFilesControllerTest: test_JS:_should_serve_core_game_module +------------------------------------------------------------------------------ +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------ +BreakEscape::RoomLazyLoadTest: test_room_response_includes_all_room_data +------------------------------------------------------------------------ + 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.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.207755"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.207693"], ["updated_at", "2025-11-25 16:27:20.207693"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/room/test_room" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::GamesController#room as HTML + Parameters: {"id"=>"1", "room_id"=>"test_room"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Serving room data for: test_room +Completed 200 OK in 1ms (Views: 0.1ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::RoomLazyLoadTest: test_should_return_room_data_for_valid_room_id +----------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.210949"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.210900"], ["updated_at", "2025-11-25 16:27:20.210900"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/room/test_room" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::GamesController#room as HTML + Parameters: {"id"=>"1", "room_id"=>"test_room"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Serving room data for: test_room +Completed 200 OK in 1ms (Views: 0.1ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::RoomLazyLoadTest: test_should_return_404_for_non-existent_room +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.213990"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.213944"], ["updated_at", "2025-11-25 16:27:20.213944"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/room/non_existent_room" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::GamesController#room as HTML + Parameters: {"id"=>"1", "room_id"=>"non_existent_room"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::RoomLazyLoadTest: test_should_return_400_when_room_id_is_missing +----------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"test_room\",\"rooms\":{\"test_room\":{\"type\":\"office\",\"objects\":[],\"connections\":{}},\"test_room_2\":{\"type\":\"office\",\"objects\":[],\"connections\":{}}}}"], ["player_state", "{\"currentRoom\":\"test_room\",\"unlockedRooms\":[\"test_room\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.216722"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.216677"], ["updated_at", "2025-11-25 16:27:20.216677"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------- +BreakEscape::GamesControllerTest: test_should_show_game +------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.218192"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.218143"], ["updated_at", "2025-11-25 16:27:20.218143"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.6ms | GC: 0.1ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.7ms | GC: 0.1ms) +Completed 200 OK in 2ms (Views: 0.9ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_show_should_inject_game_configuration +---------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.222261"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.222208"], ["updated_at", "2025-11-25 16:27:20.222208"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.2ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.3ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.4ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.1ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_scenario_endpoint_should_return_JSON +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.225871"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.225816"], ["updated_at", "2025-11-25 16:27:20.225816"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/scenario" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::GamesController#scenario as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 200 OK in 1ms (Views: 0.1ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_sync_state_should_update_player_state_for_current_room +--------------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.228590"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.228543"], ["updated_at", "2025-11-25 16:27:20.228543"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started PUT "/break_escape/games/1/sync_state" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::GamesController#sync_state as HTML + Parameters: {"currentRoom"=>"reception", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (4 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------------ +BreakEscape::GamesControllerTest: test_ink_endpoint_should_return_404_for_NPC_without_story_file +------------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.231607"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.231566"], ["updated_at", "2025-11-25 16:27:20.231566"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=missing-npc" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"missing-npc", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: missing-npc +[BreakEscape] No NPCs found in scenario data +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_game_setup_has_correct_scenario_data +--------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.233850"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.233811"], ["updated_at", "2025-11-25 16:27:20.233811"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +---------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_show_should_return_HTML_with_game_container +---------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.234889"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.234850"], ["updated_at", "2025-11-25 16:27:20.234850"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::GamesController#show as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + Rendering layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb + Rendering /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application + Rendered /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/break_escape/games/show.html.erb within layouts/break_escape/application (Duration: 0.2ms | GC: 0.0ms) + Rendered layout /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/app/views/layouts/break_escape/application.html.erb (Duration: 0.2ms | GC: 0.0ms) +Completed 200 OK in 1ms (Views: 0.3ms | ActiveRecord: 0.1ms (4 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_inventory_endpoint_should_add_items +-------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.237858"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.237820"], ["updated_at", "2025-11-25 16:27:20.237820"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Game Update (0.1ms) UPDATE "break_escape_games" SET "scenario_data" = ?, "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["scenario_data", "{\"startRoom\":\"reception\",\"startItemsInInventory\":[],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[{\"id\":\"note_1\",\"type\":\"note\",\"name\":\"Test Note\",\"takeable\":true}]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:27:20.238334"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/inventory" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::GamesController#inventory as HTML + Parameters: {"action_type"=>"add", "item"=>{"type"=>"note", "name"=>"Test Note", "id"=>"note_1"}, "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] inventory endpoint: action=add, item=#"note", "name"=>"Test Note", "id"=>"note_1"} permitted: false> +[BreakEscape] validate_item_collectible: type=note, id=note_1, name=Test Note +[BreakEscape] Item collection valid: note +[BreakEscape] Adding item to inventory: note / Test Note + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"note\",\"name\":\"Test Note\",\"id\":\"note_1\"}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:27:20.239858"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +[BreakEscape] Item added successfully. Current inventory: [{"type"=>"note", "name"=>"Test Note", "id"=>"note_1"}] +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_unlock_endpoint_should_reject_invalid_attempts +------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.241190"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.241151"], ["updated_at", "2025-11-25 16:27:20.241151"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"room", "targetId"=>"office", "attempt"=>"wrong_code", "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.0ms) 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.0ms) 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=room, id=office, attempt=wrong_code, method=pin +[BreakEscape] Object not found: office +Completed 422 Unprocessable Content in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::GamesControllerTest: test_ink_endpoint_should_return_404_for_non-existent_NPC +------------------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.243338"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.243299"], ["updated_at", "2025-11-25 16:27:20.243299"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink?npc=non-existent" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"npc"=>"non-existent", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +[BreakEscape] Loading ink for NPC: non-existent +[BreakEscape] No NPCs found in scenario data +Completed 404 Not Found in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_unlock_endpoint_should_accept_correct_pin_code +------------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.245442"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.245403"], ["updated_at", "2025-11-25 16:27:20.245403"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started POST "/break_escape/games/1/unlock" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::GamesController#unlock as HTML + Parameters: {"targetType"=>"door", "targetId"=>"office", "attempt"=>"1234", "method"=>"pin", "id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) 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, attempt=1234, method=pin +[BreakEscape] Room data: locked=true, lockType=pin, requires=1234 +[BreakEscape] Room is LOCKED, method must be valid: pin +[BreakEscape] pin validation result: true +[BreakEscape] validate_unlock returning: true + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Game Update (0.0ms) UPDATE "break_escape_games" SET "player_state" = ?, "updated_at" = ? WHERE "break_escape_games"."id" = ? [["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\",\"office\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["updated_at", "2025-11-25 16:27:20.247018"], ["id", 1]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Completed 200 OK in 1ms (Views: 0.0ms | ActiveRecord: 0.2ms (5 queries, 0 cached) | GC: 0.0ms) + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::GamesControllerTest: test_ink_endpoint_should_require_npc_parameter +-------------------------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.1ms) 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\":\"reception\",\"startItemsInInventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"rooms\":{\"reception\":{\"type\":\"room_reception\",\"connections\":{\"north\":\"office\"},\"locked\":false,\"objects\":[]},\"office\":{\"type\":\"office\",\"connections\":{\"south\":\"reception\"},\"locked\":true,\"lockType\":\"pin\",\"requires\":\"1234\",\"objects\":[]}}}"], ["player_state", "{\"currentRoom\":\"reception\",\"unlockedRooms\":[\"reception\"],\"unlockedObjects\":[],\"inventory\":[{\"type\":\"lockpick\",\"name\":\"Lockpick\",\"id\":\"lockpick_1\",\"takeable\":true}],\"encounteredNPCs\":[],\"globalVariables\":{},\"biometricSamples\":[],\"biometricUnlocks\":[],\"bluetoothDevices\":[],\"notes\":[],\"health\":100}"], ["status", "in_progress"], ["started_at", "2025-11-25 16:27:20.248326"], ["completed_at", nil], ["score", 0], ["created_at", "2025-11-25 16:27:20.248287"], ["updated_at", "2025-11-25 16:27:20.248287"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 +Started GET "/break_escape/games/1/ink" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::GamesController#ink as HTML + Parameters: {"id"=>"1"} + BreakEscape::Game Load (0.0ms) SELECT "break_escape_games".* FROM "break_escape_games" WHERE "break_escape_games"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] + BreakEscape::DemoUser Load (0.0ms) 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.0ms) SELECT "break_escape_demo_users".* FROM "break_escape_demo_users" WHERE "break_escape_demo_users"."id" = ? LIMIT ? [["id", 149617800], ["LIMIT", 1]] +Completed 400 Bad Request in 1ms (Views: 0.0ms | ActiveRecord: 0.1ms (3 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_route_constraints_correctly_capture_file_extensions +-------------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_door_tile_image +--------------------------------------------------------------------------- +Started GET "/break_escape/assets/tiles/door.png" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_minigame_starters +----------------------------------------------------------------------------- +Started GET "/break_escape/js/systems/minigame-starters.js" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/minigame-starters.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/minigame-starters.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_lockpicking_minigame +-------------------------------------------------------------------------------- +Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/lockpicking-game-phaser.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_security:_cannot_access_files_outside_break_escape_directory +----------------------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/../../config/secrets.yml" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/secrets.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/js/../../config/database.yml" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/database.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/../../config/secrets.yml" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as YAML + Parameters: {"path"=>"../../config/secrets.yml"} + Rendering text template + Rendered text template (Duration: 0.0ms | GC: 0.0ms) +Completed 404 Not Found in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_load_all_required_game_files_in_correct_order +--------------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_key-operations_minigame_module +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/minigames/lockpicking/key-operations.js" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/key-operations.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/key-operations.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_asset_paths_work_without_assets_prefix_in_load_calls +--------------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_CSS_files_should_be_accessible_from_main_game +-------------------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +-------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_sound_manager_module +-------------------------------------------------------------------------------- +Started GET "/break_escape/js/systems/sound-manager.js" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"systems/sound-manager.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/systems/sound-manager.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_should_load_GAME_CONFIG_with_proper_baseURL +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_complete_asset_loading_path_for_lockpicking +------------------------------------------------------------------------------------------ +Started GET "/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"minigames/lockpicking/lockpicking-game-phaser.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_click.mp3" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_click.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_click.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_overtension.mp3" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_overtension.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_overtension.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_reset.mp3" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_reset.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_reset.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_set.mp3" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_set.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_set.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_success.mp3" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_success.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_success.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_tension.mp3" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_tension.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_tension.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_wrong.mp3" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_wrong.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_wrong.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/tiles/door_32.png" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as PNG + Parameters: {"path"=>"tiles/door_32.png"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/tiles/door_32.png (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::AssetLoadingIntegrationTest: test_test_asset_page_loads_correctly +------------------------------------------------------------------------------ +Started GET "/break_escape/test-assets.html" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as HTML + Parameters: {"filename"=>"test-assets"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/test-assets.html (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_baseURL_prevents_duplicate_asset_paths +------------------------------------------------------------------------------------- +Started GET "/break_escape/js/utils/constants.js" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"utils/constants.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/utils/constants.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_should_serve_game_core_with_asset_references +------------------------------------------------------------------------------------------- +Started GET "/break_escape/js/core/game.js" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"core/game.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/core/game.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------- +BreakEscape::AssetLoadingIntegrationTest: test_all_response_headers_are_correct +------------------------------------------------------------------------------- +Started GET "/break_escape/css/hud.css" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as CSS + Parameters: {"path"=>"hud.css"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/css/hud.css (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/js/main.js" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as JS + Parameters: {"path"=>"main.js"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/js/main.js (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) +Started GET "/break_escape/assets/sounds/lockpick_binding.mp3" for 127.0.0.1 at 2025-11-25 16:27:20 +0000 +Processing by BreakEscape::StaticFilesController#serve as MP3 + Parameters: {"path"=>"sounds/lockpick_binding.mp3"} +Sent file /home/cliffe/Files/Projects/Code/BreakEscape/BreakEscape/public/break_escape/assets/sounds/lockpick_binding.mp3 (0.0ms) +Completed 200 OK in 0ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.0ms) + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +------------------------------------------------------------------------------ +BreakEscape::MissionTest: test_published_scope_returns_only_published_missions +------------------------------------------------------------------------------ + BreakEscape::Mission Load (0.1ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? AND "break_escape_missions"."id" = ? LIMIT ? [["published", 1], ["id", 418560898], ["LIMIT", 1]] + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 636030761], ["LIMIT", 1]] + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."published" = ? AND "break_escape_missions"."id" = ? LIMIT ? [["published", 1], ["id", 636030761], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------- +BreakEscape::MissionTest: test_should_validate_uniqueness_of_name +----------------------------------------------------------------- + TRANSACTION (0.0ms) SAVEPOINT active_record_1 + BreakEscape::Mission Exists? (0.1ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" = ? LIMIT ? [["name", "test"], ["LIMIT", 1]] + BreakEscape::Mission Create (0.1ms) INSERT INTO "break_escape_missions" ("name", "display_name", "description", "published", "difficulty_level", "created_at", "updated_at", "secgen_scenario", "collection") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING "id" [["name", "test"], ["display_name", "Test"], ["description", nil], ["published", 0], ["difficulty_level", 1], ["created_at", "2025-11-25 16:27:20.271238"], ["updated_at", "2025-11-25 16:27:20.271238"], ["secgen_scenario", nil], ["collection", "default"]] + TRANSACTION (0.0ms) RELEASE SAVEPOINT active_record_1 + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" = ? LIMIT ? [["name", "test"], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +--------------------------------------------------------------- +BreakEscape::MissionTest: test_should_validate_presence_of_name +--------------------------------------------------------------- + BreakEscape::Mission Exists? (0.0ms) SELECT 1 AS one FROM "break_escape_missions" WHERE "break_escape_missions"."name" IS NULL LIMIT ? [["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction + TRANSACTION (0.0ms) begin transaction +----------------------------------------------------------------- +BreakEscape::MissionTest: test_scenario_path_returns_correct_path +----------------------------------------------------------------- + BreakEscape::Mission Load (0.0ms) SELECT "break_escape_missions".* FROM "break_escape_missions" WHERE "break_escape_missions"."id" = ? LIMIT ? [["id", 418560898], ["LIMIT", 1]] + TRANSACTION (0.0ms) rollback transaction diff --git a/test/dummy/storage/test.sqlite3 b/test/dummy/storage/test.sqlite3 index 4b0c3e6f58e8d11606928dfd42703d6dbf383ba9..ef3f15c439bd695bd16ea8fb75ab39612f6f8db5 100644 GIT binary patch delta 3073 zcmeHJTW=dh6yEV(y}rykiQ`mGX{k?nGrSa3`5yw@q40_op zGedtvM~DUb!0dpZD*F8_I?IKTz|-grnyF3XOk+$p^GRdE)JKiC%)AFJac$Vv0R;3R zeH{33{{U)YIJ8Q41Bl|xAht|6gXlizv2h*SZZj=>vD3>2^cW}(p+4q0KA9aKH}8w^%Jkt@9(HV}(}_x%MUF>YD`&?*k%MIjh09cEj= zu?{huHIZ#uAVyw$`zMAsH0UBAsirMf!qk0B%hEJg7yIvk$oN)ZYa)=qKkO;BBeS@lh<& zEH444&F%pYNWh|po|gf)sne>b4vlytp6N!04fOVcE2r?pkl@{iSQx;@gEQI#M{j{AM zJ?6U-csVw9C7x~}JCROS0%PXnJK0tfz`=6=+d%z3Oq}>@NK9_;Hqe{mT%iW)uQ`43&~kI0${o>038Gjkt);&SuW3 zszeZ-o{MT_5>+Cvf4O>b>F)0i7ZK`gbpm^2X-<-MGty$?fKLecD|~`UeG8ksWRO}9 z+wud9RCF7D`+9ouIwg8(c$0un;dk&Z{0iPI`NWUlxIjB17C~87Bw5o`EhbRgkhnlr zAYBq}f@2fWtiB`*U>l-X6lpk5zJI*z5}p4=_#4{Lh7te( delta 926 zcmaJ;Pe>F|7@u$6%OJx~4kJJ3{p7vv*^u5#ws=FGR<@O}d`;L9OyMc=qwS?~?Iw@%XZL)XZ-kc6@VopE@ep?RTL6b z0=SBdshEUtguF#tVu%@wux@p#U)uGUZ@~0N652p6HtYZ|UFd>i;9}xcl<$VL>~U3I zFd%=Dd@Vcpd#GF8Pz_R%q)-N^^g}l^vKi$b&_Ueo{z6n%27BNeujt5CIdBy6=L;fa z+O3jjY7GcvUColK-ZOkPkeE9$i>pb%?IrizuNG4e@qiUHjD!(S7*14=+F`>8NB5xk z>f`US#04r$b0RxFF?3}-d%2J$o|b?XgMzjsjJbL}GTViVWnm{G`^GIio06n<4$tFu zc8y`&KlOb6en{cM;W}9{O>$z>YTlcpgm_ 'office_key', + 'type' => 'key', + 'name' => 'Office Key' + } + @game.save! + post unlock_game_url(@game), params: { targetType: 'door', targetId: 'office_key', diff --git a/test/models/break_escape/filtered_scenario_test.rb b/test/models/break_escape/filtered_scenario_test.rb index f47437a..9d6918b 100644 --- a/test/models/break_escape/filtered_scenario_test.rb +++ b/test/models/break_escape/filtered_scenario_test.rb @@ -39,7 +39,7 @@ module BreakEscape # Create a game with custom scenario data, bypassing the generate callback mission = break_escape_missions(:ceo_exfil) player = break_escape_demo_users(:test_user) - + game = Game.new( mission: mission, player: player, @@ -47,14 +47,14 @@ module BreakEscape ) # Manually skip callback and save game.save(validate: false) - + filtered = game.filtered_scenario_for_bootstrap - + # Check top-level fields are preserved assert_equal "Test mission", filtered["scenario_brief"] assert_equal "start", filtered["startRoom"] assert filtered["startItemsInInventory"].present? - + # Check rooms structure exists assert filtered["rooms"].present? assert filtered["rooms"]["start"].present? @@ -64,20 +64,20 @@ module BreakEscape test 'filtered_scenario_for_bootstrap preserves navigation structure' do mission = break_escape_missions(:ceo_exfil) player = break_escape_demo_users(:test_user) - + game = Game.new(mission: mission, player: player, scenario_data: @scenario_data) game.save(validate: false) - + filtered = game.filtered_scenario_for_bootstrap - + start_room = filtered["rooms"]["start"] - + # Keep connections for navigation assert_equal({ "north" => "next_room" }, start_room["connections"]) - + # Keep type for room rendering assert_equal "room_office", start_room["type"] - + # Keep lock info for validation assert_equal false, start_room["locked"] end @@ -85,14 +85,14 @@ module BreakEscape test 'filtered_scenario_for_bootstrap removes objects and npcs' do mission = break_escape_missions(:ceo_exfil) player = break_escape_demo_users(:test_user) - + game = Game.new(mission: mission, player: player, scenario_data: @scenario_data) game.save(validate: false) - + filtered = game.filtered_scenario_for_bootstrap - + start_room = filtered["rooms"]["start"] - + # Objects and NPCs should be removed assert_nil start_room["objects"] assert_nil start_room["npcs"] @@ -101,14 +101,14 @@ module BreakEscape test 'filtered_scenario_for_bootstrap preserves lock requirements' do mission = break_escape_missions(:ceo_exfil) player = break_escape_demo_users(:test_user) - + game = Game.new(mission: mission, player: player, scenario_data: @scenario_data) game.save(validate: false) - + filtered = game.filtered_scenario_for_bootstrap - + locked_room = filtered["rooms"]["next_room"] - + # Keep lock data for server-side validation assert_equal true, locked_room["locked"] assert_equal "key", locked_room["lockType"] @@ -118,17 +118,17 @@ module BreakEscape test 'filtered_scenario_for_bootstrap does not modify original' do mission = break_escape_missions(:ceo_exfil) player = break_escape_demo_users(:test_user) - + game = Game.new(mission: mission, player: player, scenario_data: @scenario_data) game.save(validate: false) - + original_rooms = game.scenario_data["rooms"].keys filtered = game.filtered_scenario_for_bootstrap - + # Original should still have all data assert game.scenario_data["rooms"]["start"]["objects"].present? assert game.scenario_data["rooms"]["start"]["npcs"].present? - + # Filtered should not assert_nil filtered["rooms"]["start"]["objects"] assert_nil filtered["rooms"]["start"]["npcs"] diff --git a/test/models/break_escape/game_test.rb b/test/models/break_escape/game_test.rb index 9aa6204..fd8c494 100644 --- a/test/models/break_escape/game_test.rb +++ b/test/models/break_escape/game_test.rb @@ -68,7 +68,7 @@ module BreakEscape @game.player_state['inventory'] = [ { 'type' => 'key', 'key_id' => 'office1_key', 'name' => 'Office Key' } ] - + result = @game.validate_unlock('door', 'office1', '', 'key') assert result, "Should unlock door with correct key in inventory" end @@ -86,7 +86,7 @@ module BreakEscape @game.player_state['inventory'] = [ { 'type' => 'key', 'key_id' => 'wrong_key', 'name' => 'Wrong Key' } ] - + result = @game.validate_unlock('door', 'office1', '', 'key') assert_not result, "Should reject unlock without required key" end @@ -102,7 +102,7 @@ module BreakEscape } } @game.player_state['inventory'] = [] - + result = @game.validate_unlock('door', 'office1', '', nil) assert_not result, "Should reject locked door without unlock method" end @@ -121,7 +121,7 @@ module BreakEscape @game.player_state['inventory'] = [ { 'type' => 'lockpick', 'name' => 'Lock Pick Kit' } ] - + result = @game.validate_unlock('door', 'office1', '', 'lockpick') assert result, "Should unlock door with lockpick" end @@ -139,7 +139,7 @@ module BreakEscape @game.player_state['inventory'] = [ { 'type' => 'key', 'key_id' => 'office1_key', 'name' => 'Office Key' } ] - + result = @game.validate_unlock('door', 'office1', '', 'lockpick') assert_not result, "Should reject lockpick unlock without lockpick in inventory" end @@ -158,7 +158,7 @@ module BreakEscape @game.player_state['inventory'] = [ { 'type' => 'lockpick', 'name' => 'Lock Pick Kit' } ] - + # Should succeed with lockpick even without the master key result = @game.validate_unlock('door', 'secure_vault', '', 'lockpick') assert result, "Lockpick should bypass specific key requirement" @@ -178,7 +178,7 @@ module BreakEscape { 'type' => 'key', 'key_id' => 'office1_key', 'name' => 'Office Key' }, { 'type' => 'lockpick', 'name' => 'Lock Pick Kit' } ] - + # Key unlock should succeed result = @game.validate_unlock('door', 'office1', '', 'key') assert result, "Key unlock should succeed" @@ -193,7 +193,7 @@ module BreakEscape } } @game.player_state['inventory'] = [] - + result = @game.validate_unlock('door', 'reception', '', 'unlocked') assert result, "Should allow access to unlocked doors" end @@ -202,7 +202,7 @@ module BreakEscape @game.player_state['inventory'] = [ { 'type' => 'key', 'key_id' => 'office1_key', 'name' => 'Office Key' } ] - + assert @game.has_key_in_inventory?('office1_key'), "Should find key by key_id" assert_not @game.has_key_in_inventory?('wrong_key'), "Should not find missing key" end @@ -211,7 +211,7 @@ module BreakEscape @game.player_state['inventory'] = [ { 'type' => 'lockpick', 'name' => 'Lock Pick Kit' } ] - + assert @game.has_lockpick_in_inventory?, "Should find lockpick in inventory" end @@ -219,7 +219,7 @@ module BreakEscape @game.player_state['inventory'] = [ { 'type' => 'key', 'key_id' => 'office1_key', 'name' => 'Office Key' } ] - + assert_not @game.has_lockpick_in_inventory?, "Should not find non-lockpick items as lockpick" end end